Czy w grze powinienem udostępniać dane między silnikiem graficznym a silnikiem fizyki?

9

Piszę silnik gry, który składa się z kilku modułów. Dwa z nich to silnik graficzny i silnik fizyki .

Zastanawiam się, czy dobrym rozwiązaniem jest udostępnianie danych między nimi?

Tak wyglądają dwa sposoby (udostępnianie lub nie):

Bez udostępniania danych

GraphicsModel{
    //some common for graphics and physics data like position

    //some only graphic data 
    //like textures and detailed model's verticles that physics doesn't need
};

PhysicsModel{
    //some common for graphics and physics data like position

    //some only physics data 
    //usually my physics data contains A LOT more informations than graphics data
}

engine3D->createModel3D(...);
physicsEngine->createModel3D(...);

//connect graphics and physics data 
//e.g. update graphics model's position when physics model's position will change

Widzę dwa główne problemy:

  1. Wiele nadmiarowych danych (jak dwie pozycje dla danych fizycznych i graficznych)
  2. Problem z aktualizacją danych (muszę ręcznie aktualizować dane graficzne, gdy zmieniają się dane fizyki)

Dzięki udostępnianiu danych

Model{
     //some common for graphics and physics data like position
};

GraphicModel : public Model{
    //some only graphics data 
    //like textures and detailed model's verticles that physics doesn't need
};

PhysicsModel : public Model{
     //some only physics data 
    //usually my physics data contains A LOT more informations than graphics data
}

model = engine3D->createModel3D(...);
physicsEngine->assingModel3D(&model); //will cast to 
//PhysicsModel for it's purposes??

//when physics changes anything (like position) in model 
//(which it treats like PhysicsModel), the position for graphics data 
//will change as well (because it's the same model)

Problemy tutaj:

  1. physicsEngine nie może tworzyć nowych obiektów, po prostu „zakłada” istniejące z silnika3D (jakoś dla mnie wygląda to bardziej anty-niezależne)
  2. Przesyłanie danych w funkcji assingModel3D
  3. physicsEngine and graphics Engine musi być ostrożny - nie może usuwać danych, gdy ich nie potrzebuje (ponieważ drugi może ich potrzebować). Ale to rzadka sytuacja. Co więcej, mogą po prostu usunąć wskaźnik, a nie obiekt. Lub możemy założyć, że graphicEngine usunie obiekty, physicsEngine po prostu wskaże do nich.

Który sposób jest lepszy?

Co spowoduje więcej problemów w przyszłości?

Bardziej podoba mi się drugie rozwiązanie, ale zastanawiam się, dlaczego większość silników graficznych i fizycznych preferuje pierwsze (może dlatego, że zwykle tworzą tylko grafikę lub tylko silnik fizyki, a ktoś inny łączy je w grze?).

Czy mają jeszcze ukryte zalety i kontrasty?

PolGraphic
źródło
Dokładnie moje pytanie.
danijar

Odpowiedzi:

9

W dzisiejszych czasach coraz więcej silników do gier przyjmuje konstrukcję komponentów (np. Unity, Unreal). W tego rodzaju projekcie a GameObjectskłada się z listy komponentów. W twojej sytuacji może istnieć jeden MeshComponenti PhysicalComponentdrugi, oba związane z jednym przedmiotem gry.

Dla uproszczenia możesz umieścić zmienną przekształcenia świata w GameObject. Podczas aktualizacji frazy, PhysicalComponentświat przekształca się w tę zmienną. Podczas renderowania MeshComponentodczytuje tę zmienną.

Uzasadnieniem tego projektu jest rozdzielenie komponentów. Ani się MeshComponentnie PhysicalComponentznają. Zależy to tylko od wspólnego interfejsu. I łatwiej jest rozszerzyć system według składu, niż stosując pojedynczą hierarchię dziedziczenia.

Jednak w realistycznym scenariuszu może być konieczne bardziej wyrafinowane zarządzanie synchronizacją fizyki / grafiki. Na przykład symulacja fizyki może wymagać uruchomienia w ustalonym czasie (np. 30 Hz), a renderowanie może być zmienne. I może być konieczne interpolowanie wyników z silnika fizyki. Niektóre silniki fizyki (np. Bullet) mają jednak bezpośrednie wsparcie tego problemu.

Unity dostarczyło dobre referencje swoich Komponentów , które warto obejrzeć.

Milo Yip
źródło
To wcale nie odpowiada na pytanie, ponieważ 2 składniki nie mówią nic o tym, czy współużytkują dane siatki, czy nie.
Maik Semder
2
W rzeczywistości oferuje lepszy projekt, który jest całkowicie uzasadniony.
jcora
7

Silniki zwykle wybierają pierwszą opcję (własną siatkę fizyki i własną siatkę renderowania), ponieważ potrzebują bardzo różnych danych, zarówno pod względem jakości, jak i ilości.

Jakość, ponieważ silnik fizyki nie dba na przykład o współrzędne tekstury, normalne grupy i wszystkie inne wymyślne elementy renderowania. Każdy z nich oczekuje, że dane w bardzo konkretnym układzie sprowadzają się do problemów z wyrównaniem, pakowania, przeplatania danych itp.

Ilość, ponieważ siatka fizyki zwykle ma znacznie mniej trójkątów, jest to uproszczona wersja siatki renderowania o wysokiej rozdzielczości.

Odsprzęgając oba, upewniamy się, że możemy poprawić jeden, w tym zmienić jego układ danych w celu uzyskania lepszej wydajności, bez uszkadzania drugiego. Jest o wiele bardziej skalowalny.

Maik Semder
źródło
0

Oprócz świetnej odpowiedzi @Millo Yip chciałbym tylko przypomnieć, że musisz udostępnić te same dane modułowi Controls i modułowi AI, a jeśli się nie mylę, większość bibliotek audio ma pojęcie o pozycji emitera dźwięku więc musisz udostępnić dane również temu modułowi.

ManicQin
źródło
0

Jak powiedzieli inni, to dość powszechne miejsce, w którym fizyka ma swój wewnętrzny stan danych zarządzany osobno od wewnętrznego stanu danych silnika renderującego. Często zdarza się, że nawet dane transformacji (pozycja / orientacja / skala) są przechowywane osobno, zarówno od fizyki, jak i renderów, ponieważ możliwe jest istnienie obiektu gry, który nie jest narzucony przez fizykę ani nie jest renderowany, ale wymaga pozycji świata dla innej mechaniki.

Sposób, w jaki dane przechodzą od fizyki do renderowania, zależy wyłącznie od Ciebie.

Można to zrobić za pomocą procesu wysyłki między podsystemami, używając zdarzeń / komunikatów. Możesz to zrobić, udostępniając publiczny interfejs podsystemu renderowania podsystemowi fizyki, aby fizyka mogła po prostu ustawić pozycję szczególnie renderowalnego. Inną opcją jest to, że podsystem renderowania wysyła zapytanie do encji o transformację podczas aktualizacji i wykonuje aktualizację pozycji komponentu renderowania, a następnie rysuje.

Oczywiście, w zależności od gry, kilka z tych środków będzie bardziej przyjaznych dla pamięci podręcznej i będzie miało lepszą wydajność niż inne. W tym momencie nie złapałbym się zbytnio na konkretny sposób, wybrałem wzór komunikacji i spróbowałem. Możesz później łatwo przerobić tę część, aby przetestować różne sposoby optymalizacji.

Naros
źródło