Grafika 2D - dlaczego warto korzystać z arkuszy sprite?

62

Widziałem wiele przykładów renderowania duszków z arkusza, ale nie zrozumiałem, dlaczego jest to najczęstszy sposób radzenia sobie z duszkami w grach 2d.

Zacząłem od renderowania ikonek 2d w kilku aplikacjach demonstracyjnych, które stworzyłem, zajmując się każdą klatką animacji dla dowolnego typu ikonki jako jej własnej tekstury - a ta kolekcja tekstur jest przechowywana w słowniku. Wydaje się, że to działa dla mnie i całkiem dobrze pasuje do mojego przepływu pracy, ponieważ zwykle robię animacje jako pliki gif / mng, a następnie wyodrębniam klatki do poszczególnych png.

Czy istnieje wyraźna korzyść w zakresie wydajności renderowania z jednego arkusza zamiast z poszczególnych tekstur? Czy przy nowoczesnym sprzęcie, który potrafi rysować miliony wielokątów na ekranie sto razy na sekundę, czy ma to w ogóle znaczenie dla moich gier 2D, które mają do czynienia z kilkadziesiąt prostokątów 50 x 100 pikseli?

Szczegóły implementacji ładowania tekstury do pamięci graficznej i wyświetlania jej w XNA wydają się dość abstrakcyjne. Wiem tylko, że tekstury są wiązane z urządzeniem graficznym podczas ładowania, a następnie podczas pętli gry tekstury renderowane są partiami. Nie jest więc dla mnie jasne, czy mój wybór wpływa na wydajność.

Podejrzewam, że istnieje kilka bardzo dobrych powodów, dla których większość deweloperów gier 2D używa ich, po prostu nie rozumiem dlaczego.

Columbo
źródło
Nie, tak naprawdę nie ma to większego znaczenia dla twoich 50 dziwnych duszków. Ale co stracić?
Kaczka komunistyczna

Odpowiedzi:

69

Silnym argumentem przemawiającym za użyciem arkuszy sprite jest to, że liczba dostępnych tekstur na karcie graficznej może być ograniczona. Dlatego twoja biblioteka graficzna będzie musiała stale usuwać tekstury i ponownie alokować tekstury na GPU. O wiele bardziej efektywne jest jednorazowe przydzielenie dużej tekstury.

Weź również pod uwagę, że rozmiary tekstur są zwykle potęgą 2. Więc jeśli masz Duszka 50x100px, przydzielisz tekstury o rozmiarze 64x128px lub w gorszym przypadku 128x128px. To tylko marnowanie pamięci graficznej. Lepiej spakuj wszystkie duszki w teksturę 1024x1024px, co pozwoliłoby na duszek 20x10, a stracisz tylko 24 piksele poziomo i pionowo. Czasami nawet duszki o różnych rozmiarach są łączone w jeden ogromny arkusz duszka, aby użyć tekstury tak wydajnie, jak to możliwe.

Dodatek: Bardzo ważnym powodem korzystania z arkuszy sprite jest zmniejszenie liczby połączeń losowych na GPU, co może mieć znaczący wpływ na wydajność. Zostało to stwierdzone w innych odpowiedziach i dodam to w celu uzupełnienia, aby uzyskać większą widoczność.

grzmot
źródło
1
Dzięki, nie zastanawiałem się nad żadnym z tych punktów - Czy z grubsza wiesz, jaki jest limit liczby dostępnych tekstur? Nigdy nie widziałem tej statystyki wymienionej w specyfikacjach graficznych - czy limit jest w zasadzie równy ilości graficznej pamięci RAM?
Columbo,
Zwykle limitem jest pamięć GPU, tak. Myślałem, że istnieją pewne ograniczenia dotyczące liczby tekstur na starszych kartach, ale nie mogę znaleźć odniesienia, które to potwierdza.
bummzack
12
Nawet jeśli nie ma ograniczenia ilościowego, ruch autobusów do przenoszenia wielu małych obrazów nie jest tak wydajny, jak jeden (lub kilka) dużych transferów.
Mordachai
5
Dobre punkty, ale najważniejsze aspekty w celu zminimalizowania przeciągnięć rurociągu poprzez odliczanie wezwania do losowania. Procesory graficzne wolą niewielką liczbę dużych zadań niż dużą liczbę małych zadań. Umieszczenie wszystkich duszków w niewielkiej ilości dużych arkuszy oznacza, że ​​możesz raz ustawić scenę tekstową i narysować wiele przekleństw naraz. Spritebatch robi to za Ciebie. Jeśli masz więcej niż jeden arkusz, powiedz spritebatch, aby posortował według tekstury
Cubed2D
Dodanie kompresji tekstur zamieniłoby każdą wolną przestrzeń w bardzo małą, niewielką część kosztów ogólnych, a do tego wszystkiego
Joe Plante
36

Powiedziałbym, że argumentem do użycia byłaby zdolność renderowania wielu rzeczy w jednym losowaniu. Weźmy na przykład renderowanie czcionek, bez arkusza sprite'u musiałbyś wyrenderować każdy znak z osobną zamianą tekstur, a następnie wywołaniem rysowania. Rzuć je do arkusza sprite i możesz renderować całe zdania za pomocą pojedynczego wywołania rysowania (znaki różnicowe w czcionce są wybierane przez podanie różnych promieni UV dla rogów). Jest to znacznie wydajniejszy sposób renderowania, gdy bardzo realny narzut renderowania na wielu platformach powoduje zbyt wiele wywołań API.

Może także pomóc zaoszczędzić miejsce, ale przede wszystkim zależy od tego, co zapakujesz do arkusza sprite.

Roger Perkins
źródło
2
+1 Dotyka podczas losowań. (coś, czego nie widziałem w zaakceptowanej odpowiedzi)
Michael Coleman,
11

Każde losowanie ma pewien narzut. Używając arkuszy sprite, możesz grupować rysunek rzeczy, które nie używają tej samej klatki animacji (lub bardziej ogólnie wszystkiego, co jest na tym samym materiale), co znacznie poprawia wydajność. W zależności od gry może to nie mieć większego znaczenia dla nowoczesnych komputerów, ale na pewno ma to znaczenie, powiedzmy, na iPhonie.

Tetrad
źródło
2
To zdecydowanie ma znaczenie. Sprzęt graficzny został zoptymalizowany pod kątem wypychania ton wielokątów dla niewielkiej liczby szczegółowych modeli (np. Postaci), ponieważ większość gier zmierza w tym kierunku. Powoduje to, że musisz popchnąć jak najwięcej wielokątów w każdym z kilku tuzinów losowań. Silniki gier, które renderują duże sceny, takie jak miasta, często łączą wiele tekstur w jedną w locie, aby ograniczyć liczbę połączeń losowych.
jhocking
Zdecydowanie zastanawiam się, czy tekstury u, v mapowania w wielu urządzeniach 3D, a także operacje łączenia bitów korzystają z arkusza sprite.
Joe Plante
7

Oprócz względów wydajnościowych arkusze ikonek mogą być przydatne podczas tworzenia sztuki; każda postać może znajdować się w osobnym arkuszu, a wszystkie ramki można zobaczyć, przewijając. Pomaga mi zachować spójny wygląd wszystkich klatek.

Dodatkowo koduję w AS3, a każdy plik obrazu wymaga osobnej instrukcji osadzania. Wolę mieć jedno osadzenie całego arkusza sprite niż 24 osadzanie dla wszystkich ramek, nawet jeśli używam osobnej klasy zasobów.

Gregory Avery-Weir
źródło
1
+1. Chociaż OP nie korzysta z Flasha, osadzanie lub ładowanie jest również zaletą arkuszy sprite. Ma to również znaczenie, gdy zasoby są ładowane z serwera WWW, na którym preferowane jest 1 żądanie zamiast kilkuset żądań (dla każdej „ramki”).
bummzack
Zdecydowanie chcesz zmniejszyć liczbę żądań serwera dotyczących gry online. Zastanawialiśmy się, czy lepiej umieścić obrazy w formacie .swf lub arkuszu sprite, ponieważ oba osiągają ten główny cel (ostatecznie zdecydowaliśmy, że arkusze sprite są mniej pracochłonne dla naszych artystów).
jhocking
7

Innym powodem, dla którego warto używać arkuszy sprite w XNA, jest to, że przy opracowywaniu Xbox360 występuje znany problem z długim czasem wdrażania / ładowania w stosunku do liczby plików, które masz w swoim projekcie. Tak więc połączenie wielu małych plików obrazów w jeden plik obrazu pomoże zwalczyć ten problem.

George Clingerman
źródło
5

Nie będę tutaj wspominał o pamięci / GPU, ponieważ takich odpowiedzi jest wystarczająco dużo.

Zamiast tego może oczyścić twoją sztukę podczas pracy nad nią - i później. Zamiast przewijać 10 zdjęć, aby zobaczyć cykl marszu, możesz zobaczyć wszystkie klatki za jednym razem. Jeśli chcesz to rozpowszechnić, masz tylko 1 plik do rozwiązania zamiast 10.

A potem czystsze (z organizacyjnego punktu widzenia) jest posiadanie character.png i wroga.png nad characterwalk01 przez characterwalk10, następnie characterattack01 do characterattack05 i trwa.

Kaczka komunistyczna
źródło
4

Pamięć graficzna nie ma nadmiernego zarządzania pamięcią, takiego jak systemy plików na dyskach; przeciwny przypadek: jest prosty i szybki .

Jednym z takich prostych i szybkich zmian w pamięci może być posiadanie tylko jednego gigantycznego duszka 4096 x 4096, który jest cięty na wiele mniejszych duszek przez połowę jego szerokości i / lub wysokości. (Istnieje podobna 1-wymiarowa technika zarządzania pamięcią, ale zapomniałem nazwy.) Ostatecznie należy przeprowadzić defragmentację.

Aby pominąć takie zarządzanie pamięcią w czasie wykonywania , programiści wypełniają pojedyncze duże duszki wieloma mniejszymi duchami automatycznie podczas kompilacji lub nawet podczas projektowania grafiki.

comonad
źródło
3

Nie zapomnij również o operacjach we / wy, które mogą zaoszczędzić podczas inicjalizacji. Jeśli ładujesz z napędu CD, każdy plik jest dodatkowym wywołaniem We / Wy i jego wyszukiwanie może zająć trochę czasu (współczesne dyski twarde mają około 15 ms na plik, a płyty CD może 50-100 ms?). Pozwala to zaoszczędzić dużo czasu inicjalizacji, ponieważ należy pobrać tylko jeden plik. Umożliwia także systemowi operacyjnemu buforowanie tych operacji we / wy, na wypadek, gdyby aplikacja robiła coś innego (na przykład czekając na GPU).

Cechowanie
źródło
1
Z drugiej strony, jeśli chcesz rozwiązać problem z wyszukiwaniem plików, możesz mieć wszystkie swoje duszki spakowane w jednym pliku, używając niestandardowego formatu. Większość gier to robi.
tigrou
0

Oprócz większej wydajności, uważam, że jest to po prostu łatwiejsze. Wymaga to trochę dodatkowej pracy, aby upewnić się, że Twoje obrazy zawsze mieszczą się w ich granicach podczas tworzenia sztuki, ale o wiele łatwiej jest zobaczyć wszystkie obrazy, z którymi masz obecnie do czynienia.

Moim zdaniem łatwiej jest też kodować. Po prostu mam szereg obiektów, takich jak:

sheet = {
    img: (the actual image),
    rects: [
        {x:0, y:0, w:32, h:32},
        {x:32, y:0, w:32, h:32},
        {x:64, y:0, w:32, h:32}
    ]
};

sheets.push(sheet);

Następnie dla każdego elementu podaję dwie wartości, arkusz i prostokąt. Arkusz będzie indeksem w tablicy obiektów, a rect będzie indeksem w tablicy rects tego arkusza.

Bridgerrholt
źródło