Wie behebe ich Objekte, die in der Physik-Engine "knallen" oder zittern?

11

Ich habe eine einfache Physik-Engine, die Kollisionen löst, indem sie einfach die Position überlappender Körper (vorerst nur Kreise) direkt korrigiert, anstatt nur die Geschwindigkeit zu ändern oder einen Impuls anzuwenden. Die Geschwindigkeit wird erst geändert, nachdem die Auswirkungen bereits behoben sind, oder während des Integrationsteils.

Ich hatte das Problem, dass in Haufen von Objekten die oberen Objekte zu viel Druck auf die Objekte am unteren Rand des Haufens ausüben (dies existiert implizit, es gibt keine Druckmodellierung im Algorithmus), was dazu führt, dass sie durch den Boden geschoben werden. etc.

Ich wollte dies beheben, indem ich die Objekte nach ihrer y-Koordinate sortierte, damit die Kollisionen von unten nach oben aufgelöst werden. Aber jetzt zeigt die Engine ein seltsames Knallverhalten für Objekte, die eigentlich in Ruhe sein sollten (siehe gif).

Geben Sie hier die Bildbeschreibung ein

Ohne nur den Quellcode anzugeben - was könnte das sein?

TravisG
quelle
5
Alles in allem ähnelt dies dem iterativen Lösen eines linearen Gleichungssystems (oder eines nichtlinearen Systems, abhängig von Ihren Einschränkungen / Bedingungen / usw.). In beiden Fällen sehen Sie diese Artefakte, weil sie numerisch richtig sind: Zwischenzustände eines konvergierenden Prozesses. Dies zu vermeiden ist ziemlich schwierig und könnte eine Menge böser Hacks bedeuten (sowieso passiert dies im wirklichen Leben auf molekularer Ebene, und genau das haben Sie dort, um etwas im wirklichen Leben am besten zu ähneln :)). Es ist wahrscheinlich gut, box2d zu untersuchen, um ihre Lösung für impulsbasierte Dynamik zu finden.
Teodron
@TravisG Wie haben Sie das Problem gelöst? Ich sehe ein ähnliches Problem, wenn ich versuche, eine sehr einfache Physik-Engine zu implementieren.
Cheesus sagt, hör auf, Mods
1
@cheeesus Es ist eine Weile her, seit ich daran gearbeitet habe, aber ich glaube, ich habe nur mehr Iterationen mit kleineren Zeitschritten verwendet.
TravisG

Antworten:

5

Eine Lösung, die ich bei der Verwendung der Positionskorrektur gefunden habe, besteht darin, einige Iterationen durchzuführen und die Stärke mit jeder Iteration zu variieren.

doPhysics();

int num_iterations = 5;
for(int iteration=0; iteration<num_iterations; ++iteration)
{
    float strength = float(iteration+1)/num_iterations;
    correctPositions(strength);
}

Die erste Iteration hat also eine Stärke von 1 / num_iterations und die letzte eine Stärke von 1. Dies macht meine Simulationen reibungsloser und stabiler als die Verwendung derselben Anzahl von Iterationen mit einer festen Stärke.

DaleyPaley
quelle
2
Gute Lösung, aber warum funktioniert es?
Gustavo Maciel
5

Ihr Problem liegt in der Tatsache, dass Sie keinen "Ruhezustand" für Ihren Körper haben. Jedes physikalische System hat eine Menge Energie, sei es kinetisch, thermisch und so weiter. In der Realität verformen sich feste Objekte leicht und wandeln kinetische Energie in Wärme um, obwohl dies kaum messbar ist. Es ist auch erwähnenswert, dass es in Wirklichkeit kein vollständig festes Objekt gibt. Selbst dichte Materialien wie Diamant haben einen Raum zwischen den Atomen, wodurch die Atomstruktur Raum hat, sich zu biegen und kinetische Energie zu absorbieren.

Um dies relevant zu machen, befinden sich ruhende Körper in einem Zustand, in dem die einzigen wirksamen Kräfte die "Normalkraft" sind, dh die Kraft, die verhindert, dass Körper durcheinander schweben. Die Größe dieser Normalkraft ist proportional zur Dichte der Objekte und wie weit sie sich gegenseitig durchdrungen haben.

Physik-Engines nennen diesen Wert "Slop".

Hier ist der Trick: Berechnen Sie die Neigung, korrigieren Sie die Position der Körper und wenden Sie die Normalkraft basierend auf der Relativgeschwindigkeit der beiden Körper an. Berechnen Sie während der Aktualisierung der Körper selbst die kinetische Energie jedes Körpers. Wenn es unter einem Mindestwert liegt, legen Sie den Körper in den Schlaf, bis eine Kraft von ausreichender Größe auf ihn ausgeübt wird. (normalerweise doppelt so hoch wie der Mindestwert).

Ian Young
quelle
0

Warum nicht eine "klebrige" Oberfläche hinzufügen und sie allmählich in einer Ruheposition halten lassen? Wenn ein anderes Objekt darauf trifft, überträgt es etwas Energie in das Objekt, wodurch es sich bewegt, aber die klebrige Oberfläche führt dazu, dass es einen Teil dieser Energie verliert und stoppt in einer Ruheposition. Das GIF sieht so aus, als hätte es keine Reibung.

anon
quelle