Czy w przeglądarce najlepiej używać jednego ogromnego arkusza sprite lub wielu (10000) różnych plików PNG?

33

Tworzę grę w jQuery, w której używam około 10000 kafelków 32x32. Do tej pory korzystałem z nich osobno (bez arkusza ikonek). Przeciętna mapa wykorzystuje około 2000 kafelków (czasami ponownie używa PNG, ale wszystkie osobne pliki div), a zakres wydajności waha się od stabilnego (Chrome) do nieco opóźnionego (Firefox). Każdy z tych div jest pozycjonowany absolutnie za pomocą CSS. Nie muszą być aktualizowane co tyknięcie, tylko po załadowaniu nowej mapy.

Czy lepsza byłaby wydajność w przypadku korzystania z metod spriteheet dla div przy użyciu pozycjonowania tła CSS, podobnie jak w gameQuery?

Z góry dziękuję!

Nacięcie
źródło
3
Gdzie do diabła potrzebujesz 10 000 kafelków na mapę? Sugeruję, aby nie przesyłać / rysować całej mapy po stronie użytkownika. Pokaż tylko część, która jest widoczna. Gdy użytkownik się poruszy, załaduj następną sekcję. Sposób działania każdej grafiki 3D.
Deele,
Średnia mapa wykorzystuje 2000 różnych kafelków, czy tylko 2000 kafelków ogółem? Jak duże są tworzone mapy?
Nick Larsen,
Czy zastanawiałeś się nad użyciem jednego lub kilku większych obrazów jako tła i przeprowadzeniem wykrywania wielokątów kolizji dla granic?
SAHornickel,

Odpowiedzi:

50

Moja sugestia

Zbyt wiele małych plików PNG spowoduje znaczne obciążenie sieci (ze względu na rozmiar żądań HTTP, ale także nagłówek PNG i, co ważniejsze, niemożność skutecznego skompresowania). Z drugiej strony, jeden bardzo duży plik PNG ma wady, których wczytywanie zajmuje trochę czasu i musi pozostać na stałe w pamięci (40 megabajtów na 10 000 kafelków) w ciągłej części pamięci.

Polecam środek: kilka rozsądnych rozmiarów PNG, na przykład 1024 kafelki o rozmiarze 32 × 32 . Może pogrupowane według motywu (na przykład PNG z kafelkami lasu, jeden z kafelkami gór, inny z kafelkami miasta - nie znam tematu twojej gry, ale masz pomysł).

Uwaga na temat wydajności pamięci podręcznej

Ze względu na wydajność dostępu do pamięci nigdy nie powinieneś robić zbyt dużych arkuszy. Blintowanie kafelków z obrazu 128 × 8192 zawsze będzie szybsze niż blending z obrazu 8192 × 128.

Wyobraź sobie, że chcesz wstawić pierwszy kafelek na obrazie 8192 × 128. Dla uproszczenia załóżmy, że 1 piksel to 1 bajt. Pierwsze dwie linie pikseli są rozmieszczone w ten sposób (komórki zawierają w pamięci liczbę bajtów):

┌────┬────┬───┬────┬──────────┬─────┐
  0   1 │...│ 31    ....    8191 1st line of pixels: bytes 0 to 8191
├────┼────┼───┼────┼──────────┼─────┤
81928193│...│8223   ....   16383 2nd line of pixels: bytes 8192 to 16383
├────┼────┼───┼────┼──────────┼─────┤
 ..  .. │...│ ..    ....    ... 

Aby więc wstawić pierwszy wiersz pierwszego tytułu, silnik przeglądarki pobierze bajty 0do31 . Aby Blit na drugą linię , będzie pobierać bajtów 8192do8223 , i tak dalej aż do linii 32, gdzie bajty 253952do253983 są pobierane.

Całkowita liczba przetworzonych bajtów będzie wynosić 32 × 32. Jednak całkowity zakres pamięci wynosi ponad 253984 bajtów. W nowoczesnym procesorze oznacza to 32 lub 33 przeciągnięcia pamięci podręcznej . Natomiast jeśli obraz miałby rozmiar 128 × 8192, zakres pamięci wynosiłby tylko 4000 bajtów, co oznacza nie więcej niż dwa przeciągnięcia pamięci podręcznej.

Ponieważ dzisiejsze procesory są bardzo szybkie, przeciągnięcia pamięci podręcznej są bardzo drogie i zawieszają się obliczenia. Zatem użycie obrazu 128 × 8192 zamiast obrazu 8192 × 128 jest potencjalnie 8 razy szybsze, przynajmniej w teorii. W praktyce będzie to zależeć od tego, w jaki sposób realizowane jest bltingowanie: możliwe jest, że sam silnik dzieli obrazy na kafelki, aby zmniejszyć problem.

Nie jest to łatwe do prawidłowego wyjaśnienia i nie spodziewałem się, że będę dużo opracowywać. Mam nadzieję, że to ma sens!

sam hocevar
źródło
4
„Należy również pamiętać, że ze względu na efektywność dostępu do pamięci nigdy nie należy zbytnio rozszerzać arkuszy sprite. Blitting kafelków z obrazu 128 × 8192 zawsze będzie szybszy niż blitting z obrazu 8192 × 128”. - fajna ciekawość, proszę rozwinąć? :)
Grimshaw
@DevilWithin: Próbowałem wyjaśnić problem; daj mi znać, jeśli będę wystarczająco jasny!
sam hocevar,
Efektywność pamięci podręcznej jest fascynująca. Czy masz jakieś liczby na temat różnicy, jaką to robi w odniesieniu do liczby klatek na sekundę?
Gregory Avery-Weir
Niezależnie od tego, czy jest to problem, wygląda na implementację, ale jeśli API takie jak OpenGL działa w ten sposób na teksturach, to na pewno ważne jest, aby wziąć to pod uwagę, dzięki :)
Grimshaw
2
@DevilWithin: to, co napisałem, jest ważne tylko dla procesora - GPU, będąc masowo równoległym, ma bardzo różne ustawienia pamięci podręcznej i będzie przechowywać tekstury przy użyciu własnego formatu wewnętrznego, zoptymalizowanego pod kątem losowego dostępu. To jest powód, dla którego w OpenGL zalecane są kwadratowe, potęgowe dwie tekstury, i ja też bym przestrzegał tej zasady również w przypadku zestawów płytek.
sam hocevar
5

Ogromny arkusz spriterzy (prawdopodobnie) zapewni lepszą wydajność, po prostu dlatego, że jedną z największych przyczyn opóźnień jest podróż w obie strony od żądania przeglądarki do serwera do przeglądarki. 10 000 połączeń HTTP zajmie dużo, znacznie dłużej niż 1 połączenie HTTP, które zwraca plik, który jest o 10 000 większy.

Mogą być inne rzeczy, których możesz użyć, aby zmniejszyć opóźnienie, w zależności od struktury gry i tworzonego HTML.

thedaian
źródło