Tworzysz silnik 3d. Chcesz najlepszych światów wieloplatformowych. Nagle zdajesz sobie sprawę, że jeśli chcesz używać Direct3D na komputerach z systemem Windows i OpenGL na OSX / Linux, musisz poświęcić obsługiwane funkcje obu najmniej powszechnym mianownikom.
Niektórzy mogą korzystać z OpenGL w trzech systemach operacyjnych, ponieważ sam w sobie wydaje się to najmniej wspólny mianownik. Wszystko jest dobrze. Następnie musisz przenieść backend API graficznego do GX Nintendo, musisz także utworzyć ścieżkę PS3 i Xbox360.
Co robisz? Czy projektujesz własny interfejs API, który sam w sobie jest najmniej wspólnym mianownikiem, i piszesz dla niego implementacje zaplecza dla każdej platformy, czy piszesz dla każdej platformy, która ma swój oddział?
Jeśli zdecydujesz się zaprojektować własny interfejs API, czy używasz wzorca mostu lub własnego voodoo? Gdzie kończy się szaleństwo, kiedy zdajesz sobie sprawę ze wszystkiego, a podejście do zlewu kuchennego musi się skończyć i w zasadzie masz oddzielny silnik dla każdej platformy jako oddziału. Lub trzymasz się wszystkiego i zlewu kuchennego i zachowujesz specyfikę platformy w specjalizacjach modułu zaplecza dla każdej platformy.
Mogę tylko rzucić okiem na Ogre3D . Jest napisany w C ++, Open source (teraz licencja MIT) i działa na każdej większej platformie od razu po wyjęciu z pudełka. Wyodrębnia API renderowania i może przełączyć się z używania DirectX na OpenGL z kilkoma ustawieniami. Jednak nie wiem wystarczająco dużo o różnicach między zestawami funkcji DirectX i OpenGL, aby stwierdzić, że obsługuje lub nie obsługuje określonej funkcji.
Torchlight od Runic Games został napisany przy użyciu Ogre i grałem w to na komputerach Mac i PC i działa bardzo dobrze na obu.
źródło
Nie zrobiłem tego dla grafiki, ale stworzyłem wieloplatformowy zestaw narzędzi audio (PC / XBOX / PS2). Poszliśmy drogą tworzenia własnego interfejsu API z funkcją najmniej powszechnego mianownika, a także opcjonalnymi funkcjami specyficznymi dla platformy. Oto kilka wyciągniętych wniosków:
Kluczem jest zdefiniowanie ścieżki przetwarzania, która zawiera podstawowe możliwości każdej platformy i umożliwia rozwój. Aby to zrobić, musisz naprawdę zrozumieć niskopoziomowy interfejs API każdej platformy, aby móc zidentyfikować odpowiednie abstrakty. Upewnij się, że łańcuch działa na najmniej wydajnej platformie, zapewniając jednocześnie dostęp do zaawansowanych funkcji najskuteczniejszej formy. Wykonaj pracę, aby to naprawić, a zaoszczędzisz wiele wysiłku później.
W przypadku audio łańcuch był podobny
SoundSources -> [Decoders] -> Buffers -> [3D Positioner] ->[Effects] -> Players
.Może to być grafika
Model -> Shapes -> Positioner -> Texturer -> [Lighting] -> [Particle Effects] -> Renderer
. (To chyba kompletnie zły zestaw, nie jestem facetem od grafiki).Napisz interfejs API, który obsługuje Twoje podstawowe obiekty, oraz interfejs zaplecza specyficzny dla platformy, który odwzoruje interfejs API na funkcje niskiego poziomu. Zapewnij najlepszy wysiłek dla każdej możliwości. Na przykład na PC i XBOX pozycjonowanie dźwięku 3D przeprowadzono z wykorzystaniem możliwości HRTF chipów dźwiękowych, podczas gdy PS2 wykorzystywał proste przesuwanie i zanikanie. Silnik graficzny może zrobić coś podobnego z oświetleniem.
Zaimplementuj jak najwięcej interfejsu użytkownika, używając neutralnego kodu platformy. Kod do dołączania obiektu pogłosu do obiektu dźwiękowego lub zasobu tekstury do obiektu kształtu powinien być całkowicie powszechny, podobnie jak kod do iteracji i przetwarzania aktywnych obiektów. Z drugiej strony obiekty niskiego poziomu mogą być całkowicie specyficzne dla platformy, z wyjątkiem wspólnego interfejsu.
Upewnij się, że interfejs API lub pliki konfiguracyjne pozwalają użytkownikowi określić opcje specyficzne dla platformy. Staraliśmy się unikać pchania kodu specyficznego dla platformy na poziom gry, utrzymując go w plikach konfiguracyjnych: plik konfiguracyjny jednej platformy może określać „efekt: SuperDuperParticleGenerator”, podczas gdy inny mówi „efekt: SoftGlow”
Zdecydowanie rozwijaj platformy równolegle. Upewnij się, że interfejsy specyficzne dla platformy są dobrze zdefiniowane i można je testować samodzielnie. Zapobiega to często „czy to poziom platformy czy poziom interfejsu API?” problemy podczas debugowania.
źródło
Piszę silnik gry open source o nazwie YoghurtGum dla platform mobilnych (Windows Mobile, Android). To był jeden z moich dużych problemów. Najpierw rozwiązałem to w ten sposób:
Czy zauważyłeś
void*
? Jest tak, ponieważRenderMethodDirectDraw
zwraca powierzchnię DirectDraw, aRenderMethodDirect3D
zwraca pulę wierzchołków. Wszystko inne również zostało podzielone. MiałemSprite
klasę, która miała alboSpriteDirectDraw
wskaźnik, alboSpriteDirect3D
wskaźnik. To trochę do dupy.Ostatnio ostatnio dużo przepisuję. To, co mam teraz, to
RenderMethodDirectDraw.dll
aRenderMethodDirect3D.dll
. W rzeczywistości możesz spróbować użyć Direct3D, zawieść i zamiast tego użyć DirectDraw. To dlatego, że interfejs API pozostaje taki sam.Jeśli chcesz stworzyć duszka, nie robisz tego bezpośrednio, ale poprzez fabrykę. Następnie fabryka wywołuje poprawną funkcję w bibliotece DLL i przekształca ją w element nadrzędny.
To jest w
RenderMethod
interfejsie API:A to jest definicja w
RenderMethodDirectDraw
:Mam nadzieję, że to ma sens. :)
PS Chciałbym do tego użyć STL, ale nie ma wsparcia dla Androida. :(
Gruntownie:
EDYCJA: Tak, sensowne jest posiadanie takich wirtualnych interfejsów. Jeśli pierwsza próba się nie powiedzie, możesz wypróbować inną metodę renderowania. W ten sposób możesz zachować wszystkie metody renderowania kodu w sposób agnostyczny.
źródło
Lubię do tego używać SDL . Ma backendery renderera dla D3D, OpenGl, OpenGL ES i garść innych backendów specyficznych dla platformy, i jest dostępny dla różnego rodzaju platform i jest obecnie w fazie rozwoju, z powiązaniami z wieloma różnymi językami.
Wyodrębnia różne koncepcje renderera i udostępnia tworzenie wideo (a także obsługę dźwięku i wejścia oraz kilka innych rzeczy) w prostym, wieloplatformowym interfejsie API. Został zaprojektowany przez Sama Lantingę, jednego z głównych deweloperów Blizzarda, specjalnie w celu ułatwienia przenoszenia gier i tworzenia gier międzyplatformowych, dzięki czemu wiesz, że masz do czynienia z biblioteką wysokiej jakości.
źródło