Rozwiązanie kolizji z siłami

14

W moim silniku fizyki 2D mogę wykryć zderzenia AABB vs. AABB i rozwiązać je, znajdując najkrótszy wektor penetracji i dodając go do pozycji AABB.

W ten sposób „wypycha” pierwszy AABB poza drugi AABB, ale w ogóle nie radzi sobie ze zmianami prędkości / przyspieszenia.

Jeśli dodam przyspieszenie grawitacyjne do mojej symulacji, prędkość pierwszego dynamicznego AABB rośnie, nawet gdy spoczywa na drugim statycznym AABB. W końcu prędkość stanie się zbyt duża i kolizja nie zostanie wykryta (dynamiczny AABB spadnie przez statyczny).

Próbowałem ustawić prędkość na zero po rozdzielczości, ale najwyraźniej nie działało to dobrze i stworzyłem nierealne symulacje.

Czytam online, że rozwiązywanie kolizji przez ręczne działanie na pozycji lub prędkości jest nieprawidłowe. Próbowałem wdrożyć siły (na razie masa jest „zakodowana” 1):

void Body::applyForce(sf::Vector2f mForce) { acceleration += mForce; }

void Body::integrate(float mFrameTime)
{
    velocity += acceleration * mFrameTime;
    position += velocity * mFrameTime;

    acceleration = {0, 0};
}

Jeśli zastosuję najkrótszy wektor penetracji jako siłę podczas rozwiązywania kolizji, dynamiczny AABB zostanie „wypchnięty” ze statycznego, ale jego prędkość nigdy nie spadnie w symulacji bez grawitacji i będzie się poruszać wiecznie.

Czy istnieje sposób zastosowania siły „tymczasowej”? Siła, która zajmuje się wypychaniem pierwszego AABB z drugiego AABB, a następnie zatrzymuje się, gdy AABB już nie koliduje?

Cały kod źródłowy dostępny tutaj: https://github.com/SuperV1234/SSVSCollision

Vittorio Romeo
źródło
1
Jestem zainteresowany tym. Czy masz już jakieś rozwiązanie?
TravisG
@TravisG: jeszcze niestety. Dodam nagrodę jutro, jeśli nie otrzymam żadnej odpowiedzi.
Vittorio Romeo
Siła przede wszystkim nie jest równa przyspieszeniu. Potrzebujesz masy, aby obliczyć przyspieszenie. Jeśli modyfikujesz pozycje, aby zatrzymać penetrację dwóch ciał, powinieneś również użyć masy i na tej podstawie przesuwać oba ciała. Zastosowanie siły równej wektorowi penetracji nie ma żadnej wartości. Box2D jest oparty na impulsach, działa bezpośrednio na prędkości, może nie być „poprawny”, ale jest wystarczająco dobry. Radzenie sobie ze zmianami prędkości w silniku opartym na impulsie jest bardzo proste, więc czy możesz określić, czy ostatecznie chcesz rozwiązania opartego na sile, czy też znacznie prostsze rozwiązanie oparte na impulsie jest wystarczająco dobre.
dreta
Osobiście sugerowałbym wybranie książki o silnikach fizyki, przynajmniej przeczytanie kilku pierwszych rozdziałów fizyki newtonowskiej. Twoje założenia są niepoprawne, a próba odpowiedzi na to pytanie oznaczałaby konieczność nauczenia cię podstaw fizyki podczas próby wyjaśnienia algorytmów wysokiego poziomu rozwiązywania kolizji.
dreta
@dreta jego założenia są w porządku. Zwrócił uwagę, że jego masa dla wszystkich obiektów jest na razie po prostu „1”, co czyni sekcje kodu ważnymi. Nawiasem mówiąc, chociaż Box2D może bezpośrednio poradzić sobie z prędkościami, musi jakoś poradzić sobie z tym samym problemem. Jeśli zamiast przyłożyć siłę, Box2D zastosuje impuls, to jakoś musi poradzić sobie z faktem, że impuls nie ustępuje po oddzieleniu obiektów. Chociaż możliwe jest, że tak naprawdę wcale nie radzi sobie z tym i po prostu pozwala obiektom zachować swoją energię (w rzeczywistości byłoby tak w rzeczywistości)
TravisG

Odpowiedzi:

13

Po pierwsze, polecam korzystanie z darmowej biblioteki fizyki typu open source, takiej jak Box2D, i skupienie się na aspektach gry, które czynią ją wyjątkową! Jeśli nalegasz na ponowne wynalezienie koła, czytaj dalej ... zauważ, że wszystkie silniki fizyki są przybliżone, a podczas gdy metoda, którą przedstawię poniżej, będzie dokładniejsza niż twój obecny model, wyniki Box2D będą znacznie bardziej realistyczne.


Aby szybko modelować dokładniejszą rozdzielczość kolizji dwóch obiektów A i B:

  1. Znajdź pozycje tuż przed kolizją. Przybliżasz to już: „znajdując najkrótszy wektor penetracji i dodając go do pozycji AABB”.
  2. Znajdź prędkości bezpośrednio po zderzeniu za pomocą fizyki newtonowskiej :
    • W przypadku, gdy masa jest zakodowana na stałe jako 1, po prostu zamień prędkości (nie dotyczy to obiektów statycznych, które muszą mieć nieskończoną masę):
      • Av = Bu
      • Bv = Au
    • Jeśli obiekty A i B mają różne masy:
      • Av = (Au * (Am - Bm) + (2 * Bm * Bu)) / (Am + Bm)
      • Bv = (Bu * (Bm - Am) + (2 * Am * Au)) / (Am + Bm)
    • gdzie:
      • v: prędkość po zderzeniu
      • u: prędkość przed zderzeniem
      • m: masa (użyj największej możliwej liczby dla masy stałego, statycznego obiektu)
  3. Ustaw przyspieszenie na 0: Przyspieszenie od kolizji zostało uwzględnione powyżej w obliczeniach prędkości w kroku 2.

Proszę spojrzeć na mój przykładowy program asteroid, który demonstruje te koncepcje.


Następnie uwzględnij obiekty ułożone w stos:

Jak już zauważyłeś, używanie prędkości do symulacji obiektów ułożonych w stos / spoczynkowych nie działa dobrze: prędkość to prędkość, którą porusza się obiekt, więc jeśli spoczywa na obiekcie statycznym, prędkość powinna być bliska 0. Nie ma sensu zwiększać prędkość obiektu, aby pojawił się w spoczynku:

Jeśli dodam przyspieszenie grawitacyjne do mojej symulacji, prędkość pierwszego dynamicznego AABB rośnie, nawet gdy spoczywa na drugim statycznym AABB. W końcu prędkość stanie się zbyt duża i kolizja nie zostanie wykryta (dynamiczny AABB spadnie przez statyczny).

To, co powinno się naprawdę wydarzyć, to siła przyspieszenia, która zmierza w przeciwnym kierunku, ponieważ grawitacja powinna anulować grawitację. (To się nazywa normalna siła nacisku). Skrótem jest po prostu nie przykładanie grawitacji do ciał, które nie znajdują się w powietrzu:

  • Jedną z metod osiągnięcia tego jest utrzymanie stanu „uziemionego”:
    • Nie przykładaj grawitacji do obiektów w stanie uziemienia.
    • Jeśli obiekt zderzy się z obiektem od dołu, a jego prędkość jest bardzo mała, przechodzi w stan uziemienia.
    • Obiekt wychodzi ze stanu uziemienia, gdy jego prędkość pionowa przekracza pewną wartość dodatnią.

Aktualizacja:

  • W kategoriach laika fizyka newtonowska mówi, że całkowita energia przed i po zderzeniu musi się zgadzać. Kiedy dwa obiekty zderzają się ze sobą, ich energia jest rozdzielana. Energia to połączenie prędkości i wagi: cięższe, szybsze rzeczy mają więcej energii. To intuicyjne. Jednak intuicyjny jest dokładny sposób, w jaki wagi wpływają na redystrybucję energii.
  • Zamiana prędkości jest skrótem tylko dla dwóch dynamicznych, nieutrwalonych ciał, które mają tę samą masę (statyczne, nieruchome obiekty mają bardzo duże, nieskończone masy).
  • Skrót, gdy jedno ciało statyczne jest nieruchome, to: drugie dynamiczne, nieutrwalone ciało utrzymuje tę samą prędkość; zmienia się tylko kąt (wyobraź sobie stół bilardowy, gdy piłka uderza o poręcz. Poręcz zasadniczo ma bardzo dużą, nieskończoną masę).
  • W innych przypadkach, takich jak trzy lub więcej obiektów, należy rozwiązać pełne równania ruchu newtonowskiego (zachowanie pędu i zachowanie energii kinetycznej).
  • Nie jestem pewien, czy równania Newtona dla ruchu można rozwiązać dla więcej niż dwóch ciał. Na szczęście jednak trzy obiekty prawie nigdy nie zderzają się w tym samym czasie. Wystarczy poradzić sobie z pierwszymi dwoma zderzającymi się ciałami, a następnie poradzić sobie z następnymi kolizjami przy użyciu nowych prędkości z poprzednich rozdzielczości kolizji. Jest to dobry powód, aby kroki fizyczne były jak najmniejsze i radzić sobie z kolizjami przed wystąpieniem jakichkolwiek penetracji.
  • Zauważysz, że w moim demo asteroid powstało wiele ciał, gdy większe skały są podzielone na mniejsze. Zawsze jednak radzę sobie z kolizjami między parami ciał; nigdy wyraźnie nie obsługując kolizji z więcej niż dwoma ciałami.
Leftium
źródło
Dziękuję za szczegółową odpowiedź. Jest coś, czego nie rozumiem: zamiana prędkości działa dobrze w zderzeniu z 2 ciałami - jednak nie widzę, jak może działać, gdy wiele ciał (a także ciał statycznych) zderza się jednocześnie. Nawet bez grawitacji posiadanie ciała dynamicznego koliduje w tym samym czasie z ciałem statycznym, a inne ciało dynamiczne powoduje problemy. Ponieważ prędkość jest zamieniana, wszystko zależy od kolejności kolizji. Jeśli ciało statyczne zderzy się na końcu, ciało przestanie się poruszać. Jeśli jest dynamiczny, ciało znów się poruszy. Jak to naprawić?
Vittorio Romeo
@Vee: Dobre pytania! Ciała Three + i ciała statyczne to dwa osobne problemy. Oba adresowałem w aktualizacji. Podsumowanie: radzi sobie z kolizjami dwóch obiektów jednocześnie; ciała statyczne mają bardzo dużą, nieskończoną masę.
Leftium
Twój model kontaktów spoczynkowych jest dziwny. Kontakty spoczynkowe służą nie tylko grawitacji, powinny działać na każdą siłę. Najłatwiejszym sposobem jest usunięcie prędkości uzyskanej dzięki przyspieszeniu w poprzedniej ramce po zetknięciu. Również przy małych prędkościach możesz całkowicie usunąć restytucję, chociaż twoje obliczenia nie uwzględniają restytucji. To podejście działa na wszystkie siły, jest łatwe do wdrożenia i wygląda wystarczająco dobrze.
dreta
16

Rozwiązanie tego problemu wymaga dostosowania pozycji i ewentualnie prędkości. Silniki fizyki sztywnych ciał mają solver, który porusza obiekty w czasie z wykorzystaniem praw ruchu Newtona, a także rozwiązuje ograniczenia niepenetracyjne i tarcie. Silniki te mogą obliczyć właściwą kombinację ruchu liniowego i kątowego, aby stworzyć prawdopodobne trajektorie.

Jeśli chcesz tylko rozwiązać nakładanie się, możesz użyć pseudo prędkości, które generują trajektorie oddzielające bez zwiększania pędu. Odbywa się to w solverie pozycji Box2D.

Polecam pobrać moje prezentacje GDC z 2006 i 2007 roku tutaj:

http://code.google.com/p/box2d/downloads/list

Możesz także spojrzeć na Box2D Lite dla uproszczonej implementacji.

Erin Catto
źródło
+1 za uwagę, że konieczne jest również dostosowanie pozycji. Niewiele osób oddaje się temu, ale aby zwiększyć stabilność symulacji, większość silników oszukuje, dostosowując pozycje bezpośrednio. Podsumowując, jeśli jest to prawdopodobne, działa w grach.
teodron
Dziękuję za odpowiedź. Chciałem wiedzieć coś, co prawdopodobnie mi umknęło w prezentacji: czy ciała statyczne są obsługiwane w Box2D w specjalny sposób? Mam na myśli - co się dzieje, gdy ciało dynamiczne uderza w ciało statyczne?
Vittorio Romeo
2

wprowadź opis zdjęcia tutaj

W prawdziwym świecie nie ma siły, która „wypycha” jedno ciało na zewnątrz innego ciała, ponieważ obiekty nigdy się nie przenikają. Najbliższą rzeczą jest normalna siła : stworzona w momencie kontaktu w rzeczywistych zderzeniach, przede wszystkim zapobiega penetracji.

Kąt tej siły normalnej jest prostopadły do ​​powierzchni styku dwóch zderzających się obiektów. Wielkość zależy od siły potrzebnej do zapobiegania penetracji. (Należy zauważyć, że należy stosować tylko składową y siły normalnej, chyba że modelowane są również inne siły, takie jak siła tarcia).

Chociaż możliwe jest jawne modelowanie siły normalnej, łatwiej jest modelować tylko jej skutki:

  1. Zapobiegaj przecięciu obiektu przez:
    • Dostosowanie prędkości poprzez rozwiązanie kolizji w momencie uderzenia. (Najlepsza)
    • Ręcznie dostosowuj pozycje ciał, aby się nie przecinały. (łatwiej) Już to robisz „znajdując najkrótszy wektor penetracji i dodając go do pozycji AABB”.
  2. Nie przykładaj siły grawitacji w miejscu, w którym normalna siła anuluje siłę grawitacji.
    • Obiekt stykający się z innym obiektem znajdującym się pod nim podlega normalnej sile. Jest to zatem kwestia śledzenia tych obiektów. (Właściwie wszystkie stykające się obiekty powinny mieć przyłożoną normalną siłę, ale nie wszystkie z nich będą miały efekt netto w odniesieniu do grawitacji.)
    • Jeśli chcesz dodać obiekty, które mogą zsuwać się w dół innych obiektów, które są pod kątem, będziesz musiał dodać siłę tarcia i składnik x siły normalnej.

Opisałem to nieco inaczej w mojej innej odpowiedzi, która dotyczy ogólnie kolizji .

Leftium
źródło