Jak naprawić obiekty „pękające” lub drżące w silniku fizyki?

11

Mam prosty silnik fizyki, który rozwiązuje kolizje, po prostu korygując bezpośrednio położenie nakładających się ciał (na razie tylko kół), a nie tylko zmieniając prędkość lub przykładając impuls. Prędkość zmienia się dopiero po rozstrzygnięciu uderzeń lub podczas części integracyjnej.

Miałem problem polegający na tym, że w stosach obiektów górne obiekty wywierają zbyt duży nacisk (istnieje to domyślnie, w algorytmie nie ma modelowania ciśnienia) na obiekty na dole stosu, co powoduje, że są one wypychane przez podłogi, itp.

Chciałem to naprawić, sortując obiekty według ich współrzędnych y, aby kolizje były rozwiązywane oddolnie. Ale teraz silnik wykazuje dziwne trzaskanie dla obiektów, które powinny być w spoczynku (patrz gif)

wprowadź opis zdjęcia tutaj

Bez podania kodu źródłowego - co to może być?

TravisG
źródło
5
Podsumowując, jest to podobne do rozwiązywania liniowego układu równań w sposób iteracyjny (lub układ nieliniowy, w zależności od ograniczeń / warunków / itp.). W obu przypadkach widzisz te artefakty, ponieważ są one poprawne numerycznie: stany pośrednie procesu konwergencji. Unikanie tego jest dość trudne i może wiązać się z wieloma nieprzyjemnymi hackami (zresztą dzieje się to w prawdziwym życiu, na poziomie molekularnym, i to właśnie tam masz, aby jak najlepiej przypominać coś w prawdziwym życiu :)). Prawdopodobnie dobrze jest zbadać box2d, aby zobaczyć ich rozwiązanie dla dynamiki opartej na impulsach.
teodron
@TravisG jak rozwiązałeś problem? Patrzę na podobny problem, gdy próbuję wdrożyć bardzo prosty silnik fizyki.
cheesus,
1
@cheeesus Minęło trochę czasu, od kiedy nad tym pracowałem, ale wydaje mi się, że użyłem więcej iteracji z mniejszymi krokami czasowymi.
TravisG,

Odpowiedzi:

5

Jednym z rozwiązań, które znalazłem podczas korzystania z korekcji pozycji, jest kilka iteracji i zmienianie siły przy każdej iteracji.

doPhysics();

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

Tak więc pierwsza iteracja ma siłę 1 / num_iterations, a ostatnia ma siłę 1. To sprawia, że ​​moje symulacje są płynniejsze i bardziej stabilne niż zwykłe używanie tej samej liczby iteracji o stałej sile.

DaleyPaley
źródło
2
Dobre rozwiązanie, ale dlaczego to działa?
Gustavo Maciel
5

Twój problem polega na tym, że nie masz stanu „spoczynku” dla swoich ciał. Każdy układ fizyki ma pewną ilość energii, czy to kinetycznej, termicznej i tak dalej. W rzeczywistości obiekt stały nieznacznie odkształca się i przekształca część energii kinetycznej w ciepło, chociaż jest to trudno mierzalne. Warto również zauważyć, że w rzeczywistości nie ma czegoś takiego jak całkowicie solidny obiekt. Nawet gęste materiały, takie jak diament, mają przestrzeń między atomami, dając strukturze atomowej miejsce na wygięcie i pochłanianie energii kinetycznej.

Aby było to istotne, ciała spoczynkowe znajdują się w stanie, w którym jedynymi działającymi siłami jest „siła normalna”, to znaczy siła, która uniemożliwia ciałom przepływanie przez siebie. Wielkość tej normalnej siły jest proporcjonalna do gęstości obiektów i odległości między nimi.

Silniki fizyki nazywają tę wartość „spadkiem”.

Oto sztuczka: oblicz nachylenie i popraw położenie ciał oraz zastosuj siłę normalną, w oparciu o prędkość względną dwóch ciał. podczas aktualizacji samych ciał oblicz energię kinetyczną każdego z ciał. Jeśli jest poniżej wartości minimalnej, uśp ciało, dopóki nie zostanie przyłożona siła o wystarczającej wielkości. (zwykle dwukrotność wartości minimalnej).

Ian Young
źródło
0

Dlaczego nie dodać do nich „lepkiej” powierzchni i sprawić, by stopniowo przylegały do ​​pozycji spoczynkowej, a kiedy uderzy w nią inny przedmiot, przenosi w to pewną energię, powodując jego ruch, ale lepka powierzchnia spowoduje utratę części tej energii i zatrzymanie w pozycji spoczynkowej. gif wygląda na to, że nie ma tarcia.

zaraz
źródło