Kleine, schnelle Objektkollisionen: Vermeidung von Tunneleffekten

13

BEARBEITEN / AKTUALISIEREN: Meine derzeit größte Frage ist, ob die "t = ..." - Gleichung von Schritt 3 eine gute Idee ist oder eine bessere Möglichkeit, dies zu tun. Die meisten anderen Probleme wurden teilweise oder vollständig behoben, aber keine Kommentare oder Antworten haben dieses Problem wirklich berührt. Auch hier ist wahrscheinlich eine analytische Lösung erforderlich, die Geschwindigkeiten und Abstände sind zu groß und die Objekte zu klein, für jede iterative / rekursive Lösung (einige sind unten in den Kommentaren vorgeschlagen), die ich mir vorstellen kann (obwohl, wenn es welche gibt) eine spezielle iterative / rekursive Lösung, die mit solchen Situationen gut zurechtkommt, dann bin ich definitiv offen dafür). Vielen Dank für Ihre bisherige Hilfe, Sie sind alle großartig und ich schätze Ihre Gedanken und Ihre Hilfe sehr!

Ich versuche, Kollisionen zwischen kleinen, schnellen Objekten zu erkennen. Dies ist eine Situation, in der das Tunneln selbst bei relativ niedrigen Geschwindigkeiten sehr leicht erfolgen kann.

Ray Casting funktioniert nicht, da hierdurch eine Kollision zwischen zwei Hochgeschwindigkeitsobjekten erkannt wird, nicht zwischen einem Objekt und einer stationären Wand. (Es sei denn, ich verstehe Ray Casting falsch?) Leistung ist SEHR wichtig. wenn möglich, möchte ich einen großen Leistungseinbruch vermeiden. Ich habe bereits einen funktionalen und sehr effektiven Quadtree ( http://en.wikipedia.org/wiki/Quadtree ) implementiert, daher werde ich ihn wie unten beschrieben modifizieren und verwenden.

Bearbeiten: Das Verringern des Zeitintervalls funktioniert nicht. Die Geschwindigkeiten sind für diese Lösung zu hoch, was bedeutet, dass die Leistungseinbußen zu hoch wären, während die überwiegende Mehrheit der Tunnelkollisionen noch ausbleibt . (Zum Beispiel könnte ich ein Objekt mit einer Größe von ungefähr 1 Einheit haben, das mit einer Geschwindigkeit läuft, die in Millionen von Einheiten pro Zeitintervall gemessen wird ...)

VORGESCHLAGENE LÖSUNG:

Schritt 1:

Erstellen Sie eine Box um die Bewegung jedes Objekts und fügen Sie diese in den Quadtree ein, um eine erste Liste möglicher Kollisionen zu erstellen. Siehe folgendes Bild (dieses Bild zeigt ein Kreisobjekt, das sich von einer Position zur nächsten bewegt, und die Bewegung, die ein Rechteck erzeugt, das in den Quadtree eingespeist wird):Durch Bewegung erzeugtes Rechteck

Schritt 2: (Vielleicht möchten Sie diesen Schritt überspringen?)

Sehen Sie sich die Liste der möglichen Kollisionen an, die durch den Quadtree erzeugt wurden. Prüfen Sie, ob sich die Rechtecke bei jeder möglichen Kollision schneiden. Wenn ja, fahren Sie mit Schritt 3 fort.

BEARBEITEN: Unten schlug Sean Middleditch vor, überstrichene Volumina / den Schnittpunkt von Kapseln zu verwenden (wenn die Objekte Kreise sind). Damit bleiben drei Optionen: 1) Überspringen Sie Schritt 2 vollständig. 2) Mach Schritt 2 auf meine Weise. 3) Mach es wie Sean. Seans Weg wird rechenintensiver sein als meine Box-Idee, aber er wird mehr falsch-positive als meinen Weg aussortieren und verhindern, dass sie den letzten Schritt erreichen.

Kann jemand aus Erfahrung sagen, welche dieser drei Möglichkeiten die beste ist? (Ich beabsichtige, diese Physik-Engine für ein paar andere Zwecke zu verwenden. Daher suche ich nach der "allgemein besten" Lösung, die in den unterschiedlichsten Situationen am schnellsten funktioniert, und nicht nur nach einem bestimmten Testfall, in dem ich die Lösung problemlos messen kann ist am schnellsten).

Schritt 3:

Verwenden Sie die folgende t = -Gleichung, wenn die Diskriminante (dh der Teil unter der Quadratwurzel) negativ oder 0 ist, keine Kollision, wenn positiv, verwenden Sie den t-Wert als Kollisionszeitpunkt (danach ist es einfach, die Positionen entsprechend anzupassen. ..wenn beide Objekte nach der Kollision weiterhin existieren). Gleichung:

t = (-1/2 sqrt ((2 a w - 2 a x + 2 b y - 2 b z - 2 c w + 2 c x - 2 d y + 2 d z) ^ 2-4 (w ^ 2- 2 w x + x ^ 2 + y ^ 2-2 y z + z ^ 2) (a ^ 2-2 a c + b ^ 2-2 b d + c ^ 2 + d ^ 2-r ^ 2-2 r ss ^ 2)) - a w + a xb y + b z + c wc x + d yd z) / (w ^ 2-2 w x + x ^ 2 + y ^ 2-2 y z + z ^ 2 ) .

Wobei (1 und 2 zur Bezeichnung der Objekte 1 und 2 verwendet werden):

t ist ein negativer Zeitwert zwischen 0 und -1, wobei 0 der aktuelle Frame und -1 der vorherige Frame ist;

a = x Position 1;

b = y Position 1;

c = x Position 2;

d = y Position 2;

w = x Geschwindigkeit 1;

x = x Geschwindigkeit 2;

y = y Geschwindigkeit 1;

z = y Geschwindigkeit 2;

r = Radius 1;

s = Radius 2;

Herleitung: (^ 2 bedeutet quadriert)

Nehmen Sie parametrische Gleichungen (zum Beispiel newxpos1 = a + t w) für die Bewegungen der Objekte und fügen Sie sie in die Abstandsformel ein (Quadrieren beider Seiten): Abstandsformel quadriert = (a + t w - (c + t x)) ^ 2 + (b + t y - (d + t * z)) ^ 2. Denken Sie daran, es wird negativ sein. Um den Kollisionszeitpunkt für zwei kreisförmige Objekte zu ermitteln, setzen wir die linke Seite gleich (r + s) ^ 2. Wenn wir t mit der quadratischen Gleichung (und einer Menge sehr langwieriger Algebra) lösen, erhalten wir die obige Gleichung "t = ...".

Meine Fragen:

1) Ist dies ein guter Weg, um es zu tun? Wird es überhaupt funktionieren? Werde ich auf unvorhergesehene Probleme stoßen? (Ich weiß, dass ich Probleme haben werde, wenn mehr als zwei Objekte auf einmal kollidieren, aber das ist mir egal, da ich nur Einwände dagegen habe, wenn sie niedrige Relativgeschwindigkeiten haben (wenn die Relativgeschwindigkeiten hoch sind) dann ist die "doof" -Lösung, die der Algorithmus liefert, "gut genug", und es ist für einen Menschen unmöglich, den Fehler zu sehen. Wenn mehr als 2 mit niedrigen relativen Geschwindigkeiten im selben Zeitschritt kollidieren, werden die meisten Lösungen trotzdem nah genug dran sein, da ich nicht vorhabe, ein paar unelastische Kollisionen zu haben)

2) Wird meine Leistung stark leiden? Ich glaube nicht, dass es so sein wird, aber wenn es so ist, gibt es einen besseren Weg, es zu tun?

3) Soll ich Schritt 2 überspringen und direkt von Schritt 1 nach 3 gehen? Offensichtlich ist Schritt 2 nicht unbedingt erforderlich, kann jedoch die Leistung verbessern (ODER es kostet möglicherweise mehr CPU-Zeit als es spart).

Alle anderen Kommentare, Vorschläge oder Kritik sind sehr willkommen. Danke für deine Hilfe!

15 Umdrehungen
quelle
1
Christer Ericson hat in seinem orangefarbenen Buch einige Informationen über Kugelabtastungen. Es gibt einige Möglichkeiten, das Problem zu lösen, aber ich stelle mir vor, Sie werden es am liebsten mögen, wenn Sie das Intervall halbieren. Es ist gut, dieses Zeug selbst abzuleiten, aber Sie sollten sich einfach das orangefarbene Buch ansehen und es vergleichen, um eine wirklich gute Erkennungsroutine zu erhalten und mehr zu erfahren.
RandyGaul
Hört sich so an, als hätten Sie bereits einen Plan. Probieren Sie ihn aus und sehen Sie, wie er funktioniert.
Trevor Powell
Ich denke, der "übliche" Weg ist, ein kleines maximales Intervall für Ihre Deltazeit zu haben. Wenn also 1000 ms vergangen sind, simulieren Sie einfach 10 x 100 ms (oder 100 x 10 ms oder 33 x 30 ms oder ähnliches).
Asche999
@RandyGaul Ich habe mir den auf Seite 215-218 beschriebenen Algorithmus angesehen, insbesondere Seite 218 (Google-Vorschau). Es ist ziemlich elegant, obwohl ich noch nicht alle Implikationen, Stärken und Schwächen durchdacht habe. Wird es viel schneller als meins sein? Wenn ja, welcher Teil meines Algorithmus ist im Vergleich zu Ericsons Rekursion langsam? Wird die Gleichung in Schritt 3 zu langsam sein? Die Rekursion lässt mich zögern, da sich einige Objekte SEHR schnell bewegen und daher in einigen Fällen eine große Menge an Rekursion erforderlich sein kann. (Auch Autsch, 70 $ für dieses Buch ...)
MindSeeker
1
@MindSeeker Ich habe keine Zeit, mich um Ihre Herleitung zu kümmern, aber ich bin überzeugt, dass die Algorithmen in Ericsons Buch wirklich gut funktionieren und wahrscheinlich schneller und robuster sind als Ihre. Sie können PDF-Versionen kostenlos online finden, wenn Sie die anderen Seiten testen möchten. Auch wenn Sie häufig Kollisionserkennungen durchführen, ist das orangefarbene Buch ein Grundnahrungsmittel.
RandyGaul

Antworten:

9

Sie haben im Wesentlichen eine etwas überbegeisterte Version von Sweep-Volumes erstellt .

Nehmen Sie die beiden Positionen des Objekts ein. "Sweep" das Objekt vom Anfang bis zum Ende. Für eine Kugel würde dies eine Kapsel erzeugen. Für eine Box würde dies ein Sechseck erzeugen (oder eine längere Box ist die Bewegung entlang einer einzelnen Achse). Für allgemeine konvexe Polygone würde dies ein anderes konvexes Polygon erzeugen.

Sie können jetzt Kreuzungstests (einschließlich Quadtree-Abfragen) mit diesem gewobbelten Volume durchführen. Sie können berechnen, wann die Kollision aufgetreten ist, die Simulation von der Startzeit bis zur Kollisionszeit fortsetzen und wiederholen.

Eine andere, etwas einfachere Möglichkeit besteht darin, das zu tun, was @ ashes999 angibt, und einfach ein kleineres Zeitintervall oder kleinere Geschwindigkeiten zu verwenden. Es gibt eine ideale Höchstgeschwindigkeit, die sich aus dem Intervall ergibt, in dem sich kein Objekt in einer einzelnen Physikinteraktion weiter als bis zu seiner engsten Seite bewegen kann. Für besonders kleine oder besonders schnelle Objekte ist es möglicherweise nicht möglich, ein angemessen kleines Intervall zu finden, das eine gute Leistung erbringt.

Unter Kollisionserkennung in Echtzeit finden Sie eine der besseren Einführungs- und Zwischenhandbücher zum Thema Kollisionserkennung.

Sean Middleditch
quelle
Danke für den tollen Input! Teilen Sie Ihre Antwort so auf, dass ich Fragen dazu stellen kann: "" Fegen Sie das Objekt vom Anfang bis zum Ende. " Bisher verfolge ich; definitiv eine Verbesserung gegenüber meiner Box-Methode. Ich werde diese Formen mit quadtree füttern und dann nach genaueren Kollisionen suchen. "Sie können berechnen, wann die Kollision aufgetreten ist." Haha leichter gesagt als getan :) Empfiehlst du, dass ich bei meiner Gleichung von Schritt 3 für den Schritt bleibe? Oder gibt es einen besseren Weg? Dies ist der wirklich kritische Teil.
MindSeeker
[Fortsetzung] "Noch eine Option ..." Ich habe über diese Option nachgedacht, aber leider sind die Geschwindigkeiten zu hoch. Siehe mein Kommentar Antwort auf @ ashes999 und bearbeiten Sie oben für weitere Informationen. Vielen Dank für Ihre Hilfe!
MindSeeker
Die einzige Möglichkeit, die Leistung zu kennen, besteht darin, sie zu testen, zu messen und zu sehen. Ich habe einige "offensichtlich" ineffiziente Codes gesehen, die die effizienten Versionen zuvor massiv übertroffen haben, normalerweise aus nicht intuitiven Gründen. Fragen Sie nicht, was am schnellsten ist. testen und herausfinden.
Sean Middleditch
Fair genug, ich werde weitermachen und meine Methode ausprobieren, modifiziert wie Sie vorgeschlagen haben. Meine Frage im Kommentar bleibt jedoch bestehen: "Sie können berechnen, wann die Kollision aufgetreten ist." Empfehlen Sie, dass ich mich für diesen Schritt an meine Gleichung aus Schritt 3 halte? Oder gibt es einen besseren Weg? Dies ist der schwierigste Teil des Problems, denke ich. Durchlaufvolumen können mir, wenn ich sie richtig verstehe, sagen, dass sich die Pfade der Objekte kreuzen, können mir aber nicht sagen, ob / wann die Objekte selbst kollidieren.
MindSeeker
1
@MindSeeker Swept-Geometrie wird als Raycast übertragen, es sei denn, Sie übertragen die Form anstelle eines Strahls. Die Methode sollte also so aussehen, als würde man für alle sich schnell bewegenden Objekte Strahlen mit "Strahlen" anstelle von nur einem Strahl gegen ein stationäres Objekt werfen. Nachdem Sie mögliche Kollisionen aus den "Strahlen" ermittelt haben, müssen Sie die Zeit für beide "Strahlen" auflösen, um sicherzustellen, dass sie sich zur gleichen Zeit am gleichen Ort befanden.
Stonemetal
2

Der in der Frage vorgeschlagene Algorithmus funktioniert hervorragend: Er ist schnell und absolut genau , auch wenn sich die Objekte mit extremer Geschwindigkeit bewegen. Ich habe einen Quadtree implementiert. Nachdem ich die Boxen aus Schritt 1 in den Quadtree eingegeben hatte, stellte ich fest, dass Schritt 2 unnötig war: Mein Programm lief fast so schnell wie zuvor.

Ich benutze diesen Algorithmus jetzt seit ein paar Monaten und er scheint perfekt zu sein, um t, den Zeitpunkt der Kollision, zu bestimmen. Da es im Web anscheinend nichts Besseres gibt, kann ich die Verwendung dieses Produkts nur empfehlen. (Einige der Antworten in den anderen Antworten und Kommentaren oben sind großartig, aber sie erfüllen entweder nicht ganz die in der Frage angegebenen Anforderungen, oder der Autor war in Bezug auf etwas sehr zweideutig und kam bei der Frage nach der Zweideutigkeit nicht zurück, um zu antworten ).

2 Umdrehungen
quelle
1

Ich habe noch nicht genug Reputation, um einen Kommentar abzugeben, aber ich möchte hinzufügen, dass mit dem, was Sean Middleditch oben erwähnt hat, es möglich ist, Ihr "t" zu berechnen. Zumindest wenn ich seine Antwort verstanden habe und du richtig fragst.

Hier ist ein Link zu einer fantastischen Antwort von Sam Hocevar, der die beste Erklärung dafür liefert, die ich je gefunden habe (er hat auch Bilder gezeichnet, Hurra!)

/gamedev//a/55991/112940

Ob das schneller ist als deine eigene Methode, kann ich nicht sagen, aber er gibt dir sicher alles, was du brauchst, um es zu implementieren und mit deiner zu vergleichen.

Um zu vermeiden, dass nur Links beantwortet werden, fasse ich seine Idee kurz zusammen:

  1. Berechnen Sie den Minkowski-Unterschied zwischen den beiden Begrenzungsrahmen
  2. Wirf unter Verwendung der Relativgeschwindigkeit zwischen dann einen Strahl / ein Liniensegment vom Ursprung zu dem durch die Minkowski-Differenz erzeugten Kästchen, um den Schnittpunkt zu erhalten
  3. Wenn der Strahl trifft, dividieren Sie die Distanz, die Ihr Strahl zurücklegt, durch die Länge des Vektors, der die relative Geschwindigkeit darstellt, und Sie erhalten Ihr "t".
  4. Klicken Sie auf den Link, den ich oben bereitgestellt habe, und sehen Sie sich eine schöne Erklärung von all dem mit vielen Bildern an. Es ist beeindruckend.
user1593842
quelle