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ę!


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
├────┼────┼───┼────┼──────────┼─────┤
│8192│8193│...│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!


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.