Ist die Physik-Engine in der Lage, diese Komplexität zu verringern, indem beispielsweise nahe beieinander liegende Objekte gruppiert und innerhalb dieser Gruppe auf Kollisionen geprüft werden, anstatt gegen alle Objekte zu vergleichen? (Beispielsweise können ferne Objekte aus einer Gruppe entfernt werden, indem die Geschwindigkeit und der Abstand zu anderen Objekten betrachtet werden.)
Wenn nicht, ist die Kollision dann für Kugeln (in 3d) oder Scheiben (in 2d) trivial? Soll ich eine Doppelschleife erstellen oder stattdessen ein Array von Paaren erstellen?
EDIT: Ist die Kollisionserkennung für Physik-Engines wie bullet und box2d immer noch O (N ^ 2)?
Antworten:
Die räumliche Teilung ist im schlimmsten Fall immer O (N ^ 2), und darum geht es in der Informatik bei der Komplexität.
Es gibt jedoch Algorithmen, die in der linearen Zeit O (N) arbeiten . Alle basieren auf einer Art Sweep-Linie.
Grundsätzlich müssen Sie Ihre Objekte nach einer Koordinate sortieren. Angenommen, X. Wenn Sie die Sortierung jedes Mal vor der Kollisionserkennung durchführen, ist die Komplexität O (N * logN). Der Trick besteht darin, nur zu sortieren, wenn Sie der Szene Objekte hinzufügen, und später, wenn sich etwas in der Szene ändert. Das Sortieren nach Bewegung ist nicht trivial. In der unten verlinkten Veröffentlichung finden Sie einen Algorithmus, der Bewegungen berücksichtigt und dennoch in linearer Zeit arbeitet.
Dann fegen Sie von links nach rechts. Jedes Mal, wenn Ihre Sweep-Linie den Anfang eines Objekts kreuzt, wird es in eine temporäre Liste eingefügt. Jedes Mal, wenn Ihre Sweep-Linie das Objekt verlässt, nehmen Sie es aus der Liste heraus. Sie berücksichtigen Kollisionen nur innerhalb dieser temporären Liste.
Die naive Sweep-Linie ist im schlimmsten Fall auch O (N ^ 2) (Sie lassen alle Objekte die gesamte Karte von links nach rechts überspannen), aber Sie können sie O (N) machen, indem Sie sie schlauer machen (siehe Link unten). Ein wirklich guter Algorithmus wird ziemlich komplex sein.
Dies ist ein einfaches Diagramm, wie die Sweep-Linie funktioniert:
Die Linie läuft von links nach rechts. Objekte werden nach X-Koordinaten sortiert.
Algorithmen wie diese haben die Komplexität O (C * N) = O (N).
Quelle: Zwei Jahre Kurse in Computergeometrie.
Bei der Kollisionserkennung wird dies normalerweise als Sweep and Prune bezeichnet , aber die Sweep-Linienfamilie von Algortithmen ist in vielen anderen Bereichen nützlich.
Weitere empfohlene Lektüre, die meines Erachtens außerhalb des Rahmens dieser Frage liegt, aber dennoch interessant ist: Effiziente Methoden für großflächiges Sweepen und Bereinigen mit AABB-Einfügung und -Entfernung - In diesem Artikel wird ein erweiterter Algorithmus für das Sweepen und Bereinigen vorgestellt, bei dem achsenausgerichtete Begrenzungsrahmen (AABB) verwendet werden ) mit einer Sortierung, die die Bewegung berücksichtigt. Algorigthm präsentiert in den Papierarbeiten in linearer Zeit.
Beachten Sie nun, dass dies der theoretisch beste Algorithmus ist . Es bedeutet nicht, dass es verwendet wird. In der Praxis hat der O (N ^ 2) -Algorithmus mit räumlicher Aufteilung im typischen Fall eine bessere Geschwindigkeit (nahe O (N)) und eine gewisse zusätzliche Speicheranforderung. Dies liegt daran, dass die Konstante C in O (C * N) sehr hoch sein kann! Da wir normalerweise über genügend Speicher verfügen und die Objekte in typischen Fällen gleichmäßig im Raum verteilt sind, funktioniert ein solcher Algorithmus BESSER. Aber O (N) ist die Antwort auf die ursprüngliche Frage.
quelle
Nein. Die Kollisionserkennung ist nicht immer O (N ^ 2).
Nehmen wir zum Beispiel an, wir haben einen Raum von 100x100 mit Objekten der Größe 10x10. Wir könnten diesen Raum in Zellen von 10x10 mit einem Gitter teilen.
Jedes Objekt kann sich in bis zu 4 Rasterzellen befinden (es könnte direkt in einen Block passen oder sich "zwischen" Zellen befinden). Wir könnten eine Liste von Objekten in jeder Zelle führen.
Wir müssen nur in diesen Zellen nach Kollisionen suchen. Wenn es eine maximale Anzahl von Objekten pro Gitterzelle gibt (dh es befinden sich nie mehr als 4 Objekte im selben Block), ist die Kollisionserkennung für jedes Objekt O (1) und die Kollisionserkennung für alle Objekte ist O (N).
Dies ist nicht der einzige Weg, um die Komplexität von O (N ^ 2) zu vermeiden. Es gibt andere Methoden, die für andere Anwendungsfälle besser geeignet sind - häufig unter Verwendung von baumbasierten Datenstrukturen.
Der von mir beschriebene Algorithmus ist eine Art der Raumpartitionierung , es gibt jedoch auch andere Algorithmen für die Raumpartitionierung. Weitere Algorithmen, die die zeitliche Komplexität von O (N ^ 2) vermeiden, finden Sie unter Typen von Datenstrukturen für die Raumpartitionierung.
Sowohl Box2D als auch Bullet unterstützen Mechanismen, um die Anzahl der überprüften Paare zu reduzieren.
Aus dem Handbuch , Abschnitt 4.15:
Aus dem Bullet Wiki :
quelle
O (N ^ 2) bezieht sich auf die Tatsache, dass Sie, wenn Sie N Objekte haben, herausfinden, was mit den im schlimmsten Fall N ^ 2 Kollisionsberechnungen kollidiert . Angenommen, Sie haben 3 Objekte. Um "wer trifft wen" zu finden, müssen Sie Folgendes finden:
Das sind 6 Prüfungen auf Kollisionen oder N * (N-1) Prüfungen. In der asymptotischen Analyse würden wir das Polynom erweitern und als O (N ^ 2) approximieren. Wenn Sie 100 Objekte hätten, wäre das 100 * 99, was nahe genug bei 100 * 100 liegt.
Wenn Sie also beispielsweise den Raum mit einem Octree partitionieren, wird die durchschnittliche Anzahl der Vergleiche zwischen Körpern reduziert. Wenn es möglich ist, dass sich alle Objekte in einem sehr kleinen Bereich ansammeln (z. B. wenn Sie eine Art Partikelflusssimulation durchführen, bei der sich Partikel im selben Bereich ansammeln können), kann das O (N ^ 2) immer noch bei auftreten Punkte in der Simulation (an welchen Punkten sehen Sie eine Verlangsamung).
Der ganze Punkt von O (N ^ 2) liegt also in der Natur jedes Körpers, der jeden anderen Körper in der Szene überprüft. Das ist nur die Art der Berechnung. Viele Dinge können jedoch dazu beitragen, dies billiger zu machen. Sogar ein Szenendiagramm (z. B. das Erkennen zwischen Objekten nur im selben Raum ) reduziert die Anzahl der durchzuführenden Kollisionsberechnungen erheblich, aber es ist immer noch O (M ^ 2) (wobei M die Anzahl der Objekte im Raum ist) Kollision erkannt werden gegen). Sphärische Begrenzungsvolumina führen die anfängliche Überprüfung sehr schnell durch (
if( distance( myCenter, hisCenter ) > (myRadius+hisRadius) ) then MISS
). Selbst wenn die Kollisionserkennung 0 (N ^ 2) ist, werden die Berechnungen der Begrenzungskugeln wahrscheinlich sehr schnell durchgeführt.quelle