Czy powinienem używać arkuszy sprite, z powodu lub pomimo dużej liczby zdjęć?

13

Zajmuję się tworzeniem gier 2D i mam wiele duszków. Użyłem animacji i modeli 3D do renderowania w 2D, aby nadać im wygląd „Fallout” lub „Diablo”. Jest to również łatwiejsze niż ręczne rysowanie, lol.

Musiałem już zmniejszyć liczbę klatek na sekundę do 15 klatek na sekundę, co było najniższym wynikiem, jaki mogłem obniżyć, nie powodując, że wyglądają na nierówne. Było to jednak smutne z powodu niewiarygodnie gładkich 24 klatek.

Są dwa powody, dla których to zrobiłem:

1) Ogranicz miejsce na dysku twardym. Im mniej obrazów, tym mniejsza będzie moja całkowita gra.

2) Ogranicz zużycie pamięci RAM. Im mniej obrazów do załadowania, tym bardziej prawdopodobne jest, że uniknę problemów z powiększaniem mojego ograniczenia pamięci RAM.

Gdyby jednak istniał sposób na kompresowanie obrazów w przestrzeni HDD i pamięci RAM, zrobiłbym to. Testowałem to już wcześniej i większość nie otrzymuje żadnej zmiany jakości przy nadawaniu z RGBA8888 na RGBA5555 i tylko niewielki hit przy konwersji na RGBA4444 w moim programie TexturePacker. Obecnie nie robię tego, ponieważ SFML wydaje się używać tej samej ilości pamięci, niezależnie od tego, jaki to jest typ obrazu .PNG. Zastanawiałem się, jak inaczej to załadować, ale nie znalazłem nic na ten temat.

Dużo czytałem o tym, jak radzić sobie z grami 2D. Konsensus jest przytłaczający: spakuj swoje duszki w większą teksturę, aby uzyskać doskonałą wydajność! Więc pakuję moje małe duszki do znacznie większego arkusza za pomocą TexturePacker.

Jednak planuję mieć 10-15 animacji na postać, 5 kierunków ruchu i 15-40 klatek na animację (prawdopodobnie średnio 24). Z 15 animacjami, 5 kierunkami i średnio 24 klatkami na animację; To 1800 pojedynczych klatek na znak. Jeśli zapakowane w arkusz sprite, to tylko 75 obrazów zamiast tego. (Jeden arkusz duszka na animację, na kierunek. 15 * 5)

W przypadku jednej ogromnej postaci bossa w grze nie mogę użyć arkusza sprite i muszę zaprogramować sposób, aby po prostu załadować jedno zdjęcie na raz. Nie wiem jeszcze, czy mogę to zrobić dla wydajności.

Dla postaci już spakowałem je do arkusza sprite. W przypadku pojedynczej postaci, która chodzi, wydaje się, że działa to przez większość czasu, chociaż czasami zwleka. Jednak przypisuję to mojemu źle opracowanemu kodowi, który zamienia tekstury zamiast wstępnie ładować wszystkie tekstury dla tego znaku.

Gdybym miał wstępnie załadować tekstury, ma to sens dla arkuszy sprite. Wyobrażam sobie tylko, że to zły pomysł, aby wstępnie załadować 1800 małych obrazów dla każdej postaci.

Jednak wyobrażam sobie, że przesyłanie ich do pamięci i do pamięci pojedynczo byłoby niezwykle szybkie, więc musiałbym mieć tylko jeden obraz w pamięci na raz. Czy to nie znaczy, że w danym momencie każda postać zużyłaby tylko kilka KB zamiast 45 + MB?

Wyobrażam sobie, że zabiłoby to moją wydajność, ponieważ przesyłanie strumieniowe musiałoby być niezwykle szybkie (15 obrazów wchodzących i wychodzących z pamięci i renderowanych na sekundę) i chociaż obrazy byłyby bardzo małe - lepszym pomysłem może być ładowanie arkuszy postaci zamiast tego do pamięci. Ale i tak będę musiał kodować system renderowania podobny do strumienia pojedynczego obrazu dla mojej większej postaci bossa.

Eksperymentowałem, ale nie jest to prosty proces. Zwłaszcza, że ​​pracuję nad innymi częściami silnika gry, które obecnie nie zajmują się grafiką.

Carter81
źródło
1. Nie określono ograniczeń pamięci RAM ani dysku twardego. Ile znaków musi mieć szybki dostęp? 2. W tekście jest kilka pytań, być może mógłbyś je skoncentrować pogrubieniem lub nawet podzielić je na części?
Kromster
Oh przepraszam. Niewiele. Wyobrażam sobie, że maksymalna liczba pojedynczych postaci na ekranie w tym samym czasie wynosiłaby około 40. Gdyby ludzie próbowali rozbić swoich klientów, to ... 130 jest absolutnym maksimum. Zazwyczaj typowe maksimum musiałoby wynosić 10, a absolutne maksimum byłoby nie większe niż <40. Wszystko powyżej 40 byłoby ekstremalną, ekstremalną rzadkością, z użytkownikami celowo próbującymi wcisnąć postacie bez powodu innego niż zrzut ekranu lub dla zabawy z wczytywania postaci. Wszystko powyżej 10 jest rzadkie, a wszystko około 40 jest niezwykle, niezwykle rzadkie.
Carter81
Gra jest przeznaczona wyłącznie na komputery PC (bez urządzeń mobilnych) 2D RPG, jednak nie chciałbym wykluczyć platformy mobilnej, chyba że jest to po prostu niemożliwe. Wyobrażam sobie, że ilość dostępnej pamięci RAM jest ograniczona do dowolnej pamięci RAM na komputerze użytkownika i pamięci VRAM użytkownika. Poważnie wątpię, czy będzie to bardzo duży dysk HDD. Po prostu zawsze jest prawdą, że im mniejszy dysk, tym lepiej.
Carter81,
Ile znaków UNIKALNYCH potrzebujesz na ekranie?
Kromster
Nie więcej niż 20. Wszystko powyżej byłoby prawie niemożliwe, chyba że oszukiwały. Zazwyczaj 5-10.
Carter81,

Odpowiedzi:

16

Mamy podobny przypadek z naszym remake'em RTS. Wszystkie jednostki i domy są duszkami. Mamy 18 000 duszków dla jednostek i domów oraz terenu, a także kolejne ~ 6 000 dla kolorów drużynowych (stosowanych jako maski). Długotrwale mamy również około 30 000 znaków używanych w czcionkach.

Zatem głównym powodem atlasów są:

  • mniej zmarnowanej pamięci RAM (w starszych dniach, gdy przesyłasz NPOT do GPU, rozciągałem / dopełniałem go do POT, czytam, że nadal jest tak samo z iOS i niektórymi ramami. Lepiej sprawdź zakres sprzętu, na który celujesz)
  • mniej przełączników tekstur
  • szybsze ładowanie wszystkiego w mniejszej ilości

Co nam nie zadziałało:

  • paletowane tekstury. Ta funkcja istniała tylko w OpenGL 1.x 2.x i nawet wtedy została w większości odrzucona przez twórców GPU. Jeśli jednak dążysz do OpenGL + Shaders, możesz to zrobić w kodach shaderów, w porządku!
  • Tekstury NPOT, mieliśmy problemy ze złymi ramkami i rozmytymi ikonkami, co jest niedopuszczalne w pikselach. Zużycie pamięci RAM było również znacznie wyższe.

Teraz mamy wszystko zapakowane w kilkadziesiąt 1024x1024 atlasów (nowoczesne procesory graficzne obsługują nawet większe wymiary) i to działa dobrze, jedząc tylko ~ 300 MB pamięci, co jest całkiem dobre dla gry na PC. Niektóre optymalizacje, które mieliśmy:

  • dodaj opcję użytkownika, aby używać RGB5_A1 zamiast RGBA8 (cienie szachownicy)
  • unikaj 8bit Alpha, jeśli to możliwe i używaj formatu RGB5_A1
  • ciasno upakuj duszki do atlasów (patrz algorytmy pakowania bin)
  • przechowuj i ładuj wszystko w jednym kawałku z dysku twardego (pliki zasobów powinny być generowane offline)
  • możesz także wypróbować sprzętowe formaty kompresji (DXT, S3TC itp.)

Kiedy poważnie zastanawiasz się nad przeniesieniem na urządzenia mobilne, będziesz martwić się ograniczeniami. Na razie wystarczy uruchomić grę i przyciągnąć graczy! ;)

Kromster
źródło
To było jak dotąd najlepsze rozwiązanie! Moje duszki nawet nie wyglądają inaczej w RGB5_A1 lub RGBA4444, ale oszczędza to pamięć. Twoja sugestia na czacie, aby wstępnie załadować wszystkie moje zasoby w pamięci RAM i VRAM jest idealna. Co więcej, zasugerowałeś, aby mieć opcjonalne poziomy grafiki, takie jak klient wysokiej rozdzielczości dla tych, którzy mają pamięć RAM, lub opcję zmniejszenia liczby klatek na sekundę itp. Świetne sugestie i dokładnie to, czego potrzebowałem!
Carter81,
5

Mam stycznie powiązanego odpowiedź w tutaj , ale ogólna idea jest taka, że jeśli jesteś załadunku i tekstur rysunku w różnych momentach (nie masz ładowania dodatkowych tekstur gdy jesteś rendering), to nie są dwa miejsca, gdzie co ci wpłynie na twoją wydajność:

Czas ładowania:

To jest moment, w którym umieścisz swoje tekstury w pamięci. Cała ilość danych, które wysyłasz do VRAM, co będzie przede wszystkim określić, jak długo czas ładowania będzie. Uczynienie tekstur mniejszymi formatami, takimi jak RGBA4444, przyspieszy to. Jednak jeśli nie przesyłasz tekstów w wysokich setkach megabajtów do VRAM, prawdopodobnie nie będziesz mieć tutaj wąskiego gardła. Jeśli to zrobisz, ładny ekran ładowania może ułatwić oczekiwanie.

Łączenie tekstur w atlasy będzie miało niewielki efekt, ponieważ cała ilość informacji wysyłanych do VRAM będzie taka sama. W rzeczywistości, jeśli atlujesz swoje tekstury i musisz zostawić puste miejsca w swoich atlasach, wtedy faktycznie wyślesz więcej danych do VRAM, a zatem ta część będzie wolniejsza!

Wydajność renderowania:

Gdy wszystkie tekstury znajdą się w pamięci VRAM, ich liczba nie wpłynie na wydajność renderowania. Istnieją cztery elementy, które wpływają na wydajność renderowania:

  1. Zmiany stanu renderowania : Za każdym razem, gdy zmienisz obraz, z którego chcesz renderować, poważnie wydłuży czas potrzebny do jego renderowania. Ogólnie rzecz biorąc, chcesz zminimalizować liczbę zmian stanu i możesz zmniejszyć liczbę zmian stanu, grupując kilka obrazów, które będziesz kolejno rysować, w atlasie tekstur.

    Sam atlasing nie wystarczy. Musisz atlasować w taki sposób, aby zmiany stanu były redukowane, aby uzyskać wzrost wydajności. Na przykład może się wydawać, że umieszczenie głównego bohatera w arkuszu ikonek da ci wzrost wydajności, ale jeśli rysujesz tylko jednego ikonkę z tego arkusza na ramkę, nie uzyskasz żadnego wzrostu wydajności w porównaniu do posiadania każdy duszek w osobnym pliku.

    Właściwe atlasing nie jest trywialny, ale ogólnie można bezpiecznie grupować duszki z tej samej warstwy. Na przykład posiadanie wszystkich elementów GUI w jednym arkuszu sprite jest bardzo obiecującym pomysłem, podczas gdy grupowanie potworów alfabetycznie może nie.

  2. Rysuj połączenia: Ogólnie rzecz biorąc, możesz chcieć ograniczyć liczbę swoich połączeń do minimum. Dobrą zasadą jest to, że jeśli nie ma żadnych zmian stanu renderowania między dwoma wywołaniami losowania, możesz połączyć je w jedno wywołanie losowania. Aby uzyskać bardziej zaawansowany wzrost wydajności, możesz użyć, powiedzmy, 8 próbników tekstur i grupowych wywołań rysunkowych dla każdych 8 tekstur, więc musisz zmieniać tekstury tylko co 8 tekstur.

  3. Liczba trójkątów: im więcej narysujesz trójkątów, tym dłużej będzie trzeba je narysować. Jednak we współczesnych komputerach i w większości gier 2D będziesz bardzo daleko od maksymalizacji tego. Możesz bezpiecznie narysować setki tysięcy duszków na ramkę i nadal uzyskać niesamowicie dobre liczby klatek na sekundę. Prawdopodobnie będziesz bardziej związany z procesorem, jeśli rysujesz ogromne ilości duszków, zanim pojawią się problemy z GPU.

  4. Ustawienia interfejsu API: jeśli wszystko robisz dobrze, a wciąż dziwnie mało klatek na sekundę, sprawdź ustawienia, za pomocą których rysujesz swoje duszki. Nie znam SFML, ale na przykład w Direct3D 9, tworzenie bufora wierzchołków za pomocą D3DUSAGE_DYNAMIClub w D3DPOOL_MANAGEDmoże z łatwością zwiększyć dziesięciokrotnie czas renderowania. Oczywiście użycie vSync ograniczy liczbę klatek na sekundę przy częstotliwości odświeżania monitora. Ponadto użycie niezrównanych FVF może obniżyć wydajność niektórych GPU. To samo dotyczy Direct3D 9.

    W twoim przypadku sprawdź dokumentację interfejsu API, którego używasz.

Jeśli masz tylko niewielką do umiarkowanej liczbę tekstur (mniej niż 1 GB) i rysujesz małe ilości ikonek (mniej niż milion na ramkę), to pierwszą rzeczą, na którą bym spojrzał, była zmiana ustawień API i następnie zmniejszając liczbę stanów renderowania i rysując połączenia.

Panda Piżama
źródło
Jeśli nie dbam o czasy ładowania, czy mogę założyć, że jeśli nie zabraknie mi pamięci RAM lub VRAM, powinienem wcześniej załadować wszystko do pamięci?
Carter81,
Interesuje mnie tylko wszystko PONIEWAŻ Boję się, że zabraknie pamięci RAM / VRAM. Nie wiem dlaczego, ale przeraża mnie to, że użytkownicy grający w moją grę będą się zawieszać za każdym razem, gdy spróbują załadować się do obszaru, w którym znajduje się zbyt wiele unikalnych duszków, lub ulegnie awarii, gdy zbyt wiele postaci wejdzie na ekran. Jeśli się nie mylę i każda pojedyncza ikona zużywa 96 KB, to jeśli każda unikalna postać ma 15 animacji, 5 kierunków i średnio 24 klatki na animację - każda pojedyncza postać w pełni załadowana ma 173 MB. Na ekranie może być jednocześnie 10, a może nawet więcej, unikatowych postaci.
Carter81
@KromStern: Jeśli atlasujesz i musisz zostawić puste miejsca (wypełnienie), dane będą większe, a zatem czasy ładowania będą dłuższe. Oczywiste jest, że przyczyną dłuższych czasów ładowania jest pusta przestrzeń, a całkowity czas ładowania jest związany z całkowitą ilością danych, a nie z ilością tekstur. Nie widzę w tym nic wprowadzającego w błąd i myślę, że osoba posiadająca wystarczającą wiedzę, aby zrozumieć pierwotne pytanie, będzie w stanie połączyć kropki i wyciągać własne wnioski we wszystkich przypadkach, gdy tekstury i atlasy to PoT i nPoT.
Panda Pajama
1
@ Carter81: Musisz wybrać docelową konfigurację sprzętową, taką jak „i5, 1 GB pamięci RAM, NVidia GT260, dysk twardy 400 MB” i pracować z tego. Zawsze będą komputery, które są słabsze i mają mniej pamięci RAM.
Kromster,
Oczywiście nie potrzebują wszystkich 15 animacji w danym momencie. Jednak co się stanie, jeśli wszystkie 10 unikalnych postaci przejdzie jednocześnie w „Tryb walki”, a zatem wymaga 5 zestawów animacji (chód, bieg, bezczynność, brak walki itp.), Aby zostać zamienionych na 5 dodatkowych (chód bojowy, walczyć bezczynnie, walczyć itp.)? Boję się zamiany tekstur, ponieważ kiedy próbowałem to zrobić za pomocą SFML, spowodowało to zauważalne zawieszenie lub wstrzymanie klienta podczas przełączania atlasów tekstur. Nie wiem, jakie byłoby moje wąskie gardło w przypadku różnych strategii radzenia sobie z wieloma duszkami.
Carter81