Tekstury

Postępuj zgodnie z tymi sprawdzonymi metodami, aby zoptymalizować wygląd i działanie tekstur w swojej grze na Androida.

Tekstury są podstawowym elementem Twojej sztuki 3D. Gry 3D, które działają dobrze na największej liczbie urządzeń, zaczynają się od grafiki 3D, która została zaprojektowana z myślą o najlepszym wykorzystaniu procesorów graficznych. W tym przewodniku omawiamy optymalizacje i sprawdzone metody dotyczące tekstur na urządzeniach mobilnych, dzięki którym możesz zwiększyć wydajność gry, zminimalizować zużycie energii przy zachowaniu wysokiej jakości obrazu.

Część tego artykułu została przygotowana na podstawie pracy współtworzonej przez Arm Limited.

Twórz atlasy tekstur

atlas tekstur to tekstura przeznaczona do przechowywania danych obrazu różnych obiektów graficznych, takich jak siatki 3D i sprite'y 2D. Zamiast, aby każdy obiekt miał własną teksturę, do łączenia obrazów z poszczególnych obiektów używana jest tekstura atlasu.

Siatki o wspólnym atlasie tekstury
Rysunek 1. Żółte podświetlenie w wyrenderowanej scenie (po lewej) oznacza siatki z atlasem tekstury (po prawej).

Minimalizowanie liczby wywołań wywoływanych w ramce gry to ważny element uzyskiwania optymalnej wydajności renderowania. Zastosowanie tej samej tekstury do różnych obiektów to jeden z czynników wpływających na połączenie ich w jedno wywołanie rysowania. Zmniejszenie liczby wywołań rysowania jest szczególnie ważne w przypadku gier powiązanych z procesorem, ponieważ każde wywołanie obciążające procesor jest przetwarzane przez sterownik karty graficznej. Atlasy tekstur zmniejszają też liczbę plików zasobów tekstur w danych gry w czasie działania. Setki, a nawet tysiące tekstur, można połączyć w znacznie mniejszą liczbę plików atlasów tekstur.

Układ atlasu tekstur należy zaplanować podczas tworzenia siatek 3D. Jeśli atlas został utworzony przed utworzeniem zasobu sieci typu mesh, należy go rozpakować UV po atlasie tekstury. Jeśli atlas zostanie utworzony po utworzeniu atlasu za pomocą narzędzi do scalania lub tworzenia atlasów w oprogramowaniu do malowania, trzeba zmienić układ wyspy UV zgodnie z teksturą.

Grupowanie wywołań rysowania specyficznych dla wyszukiwarki

Silnik gry Unity ma funkcję grupowania wywołań wywoływanych przez rysowanie, która może automatycznie łączyć obiekty. Aby kwalifikować się do automatycznego grupowania, obiekty muszą mieć wspólny materiał, w tym tekstury, oraz być oznaczone jako statyczne.

Unreal Engine 4 wymaga ręcznej konfiguracji grupowania. Możesz scalić obiekty w oprogramowaniu 3D przed zaimportowaniem ich do Unreal. Zawiera również narzędzie UE4 Actor Scale, które umożliwia łączenie siatek i tworzenie plików atlasów tekstur.

Generuj mapy migowe

Mipmaps to wersje tekstury w niższej rozdzielczości. Zbiór mipmap dla danej tekstury jest nazywany łańcuchem mipmap. Każdy kolejny poziom mipmappingu w łańcuchu oznacza niższą rozdzielczość niż poprzedni poziom. Mipmaps są używane do implementacji tekstu LOD (poziomu szczegółów) tekstur podczas renderowania. Gdy mipmappowana tekstuura jest powiązana ze etapem tekstury, sprzęt graficzny korzysta z przestrzeni tekstury zajmowanej przez fragment, aby wybrać poziom z łańcucha mipmap. Podczas renderowania sceny 3D obiekt znajdujący się dalej od kamery używa mipmapę o niższej rozdzielczości niż ten sam obiekt bliżej kamery.

Tekstura zmigrowana zużywa więcej pamięci niż tekstura niezmigrowana. Dodatkowe poziomy mipmap zwiększają wykorzystanie pamięci tekstury o 33%. Jeśli tekstura jest narysowana w stałej odległości od kamery, generowanie mimap jest niepotrzebne.

Łańcuch mipmap z podstawowej rozdzielczości tekstury 512 x 512 pikseli
Rysunek 2. Łańcuch mipmap, którego podstawowa rozdzielczość tekstury wynosi 512 x 512 pikseli.

Właściwe korzystanie z map mipmap poprawia wydajność GPU. Dostępność poziomów mipmap o niższej rozdzielczości zmniejsza wykorzystanie przepustowości pamięci i poprawia przechowywanie pamięci podręcznej tekstur.

Mipmapping może również poprawić jakość obrazu, ograniczając tworzenie aliasów tekstur. Efekt migotania tekstur można zaobserwować w obszarach oddalonych od kamery.

Przykład aliasowania tekstur
Rysunek 3. Przykład aliasu tekstur. Jeden obraz jest renderowany bez mipmap (po lewej), a drugi z mipmapami (po prawej). Aliasowanie tekstur można zaobserwować w czerwonym prostokątu na obrazie po lewej stronie.

Szczegóły mipmapy dla konkretnej wyszukiwarki

Unreal Engine 4 wymaga dwóch wymiarów tekstury (np. 512 x 1024, 128 x 128), aby można było stosować mipmappowanie. Łańcuchy mipmap nie będą generowane, jeśli jeden lub oba wymiary tekstury nie są potęgą 2.

Mechanizm Unity automatycznie skaluje tekstury o wymiarach niebędących potęgą 2 w celu utworzenia mipmap. Aby uniknąć takiego skalowania, upewnij się, że źródłowe pliki tekstur są dwuwymiarowe.

Wybierz odpowiednie tryby filtrowania tekstur

Filtrowanie tekstur to sprzętowa funkcja renderowania, która wpływa na wygląd wyrenderowanego trójkąta. Właściwe użycie filtrowania tekstur może poprawić wizualną jakość sceny. Dostępnych jest wiele trybów filtrowania tekstur. Każdy z nich zapewnia inną równowagę między poprawą renderowania a kosztami. Koszt obejmuje zarówno czas przetwarzania, jak i przepustowość pamięci. Trzy powszechnie dostępne tryby filtrowania tekstur to: najbliższy (lub punkt), dwukierunkowy i trójliniowy. Anizotropowy to dodatkowa metoda filtrowania tekstur, którą można łączyć z filtrowaniem dwuliniowym lub trójliniowym.

Najbliżej

Najbliższy to najprostszy i najtańszy tryb filtrowania tekstur. Najbliższe próbki to jeden teksel o określonych współrzędnych tekstury źródłowej. Trójkąty renderowane jako zbliżeniowe mają efekt zniekształceń lub pikseli, zwłaszcza w pobliżu aparatu.

Dwuliniowy

Filtrowanie dwukierunkowe umożliwia próbkowanie 4 teksów otaczających określone współrzędne w tekstury źródłowej. Uśrednianie tych 4 teksów pozwala określić kolor tekstury tego fragmentu. Filtrowanie dwukierunkowe zapewnia gładszy gradient między pikselami, co pozwala uniknąć efektu bloków przy najbliższym filtrowaniu. Trójkąty renderowane blisko obiektywu będą rozmyte, a nie pikselizowane. Dane dwuliniowe kosztują więcej niż najbliższe ze względu na dodatkowe próbki tekseli i uśrednianie.

Porównanie filtrowania najbliższego i dwuliniowego
Rysunek 4. Porównanie filtrowania tekstur najbliższego (po lewej) i dwuliniowego (po prawej).

Trójliniowy

Jeśli renderujesz siatkę, w której odległość wierzchołków od kamery różni się, podczas renderowania można wybrać wiele poziomów mipmappingu. Zmiany między dwoma poziomami mipmappingu mogą prowadzić do wyraźnego cięcia w punkcie przejścia. Filtrowanie trójliniowe zmiękcza te przejścia przez filtrowanie dwuliniowe na 2 różnych poziomach mimpmap i interpolację wyników. Użycie wielu mip i interpolacji sprawia, że metoda trójliniowa jest droższa od modelu dwuliniowego.

Porównanie filtrowania dwuliniowego i trójliniowego
Rysunek 5. Porównanie filtrowania tekstur dwuliniowych (po lewej) i trójliniowego (po prawej). Powiększony obszar kontrastuje różnice w renderowaniu wzdłuż przejść mipmmap.

Anizotropowe

Filtrowanie anizotropowe poprawia jakość wizualną teksturowanych siatek, które są renderowane pod skrajnym kątem względem kamery. Typowym przykładem tego typu siatki jest płaszczyzna podłoża. Filtrowanie anizotropowe wymaga do działania tekstur zmigrowanych. Możesz skonfigurować współczynnik lub poziom filtrowania anizotropowego stosowany podczas renderowania. Koszt filtrowania anizotropowego wzrasta wraz ze wzrostem poziomu.

Porównanie filtrowania anizotropowego 1x i 2x
Rysunek 6. Porównanie filtrowania biliniowego/1x-anizotropowego (po lewej) i dwuliniowego/2x anizotropowego (po prawej)

Strategia wyboru trybu

Filtrowanie dwuliniowe zapewnia zwykle najlepszą równowagę między wydajnością a jakością obrazu. Filtrowanie trójliniowe wymaga znacznie większej przepustowości pamięci i należy go używać selektywnie. W wielu przypadkach filtrowanie dwuliniowe w połączeniu z 2-krotnym filtrowaniem anizotropowym będzie wyglądać i osiągnąć lepsze wyniki niż filtr trójliniowy z filtrem anizotropowym 1x. Zwiększenie do dwukrotnego zwiększenia poziomu anizotropowego jest bardzo kosztowne i należy je przeprowadzać bardzo selektywnie w przypadku kluczowych zasobów gry.

Filtrowanie tekstur może odpowiadać nawet za połowę całkowitego zużycia energii przez GPU. Wybór prostszych filtrów tekstur w miarę możliwości to świetny sposób na zmniejszenie zużycia energii przez grę.

Zoptymalizuj rozmiary tekstur

Upewnij się, że wymiary tekstury są jak najmniejsze przy zachowaniu pożądanej jakości obrazu. Sprawdź zasoby tekstur pod kątem błędów w postaci dużych tekstur. Zasada ta dotyczy zarówno tekstur dyskretnych, jak i atlasów. Jeśli Twoja gra obsługuje wiele urządzeń, oferujących szeroki zakres rozdzielczości i wydajności, zastanów się nad utworzeniem wersji zasobów tekstur w niskiej i wysokiej rozdzielczości dla odpowiedniej klasy urządzenia.

Podczas renderowania siatki z większą liczbą tekstur rozważ selektywne zmniejszenie rozdzielczości niektórych tekstur. Na przykład przy użyciu rozproszonej tekstury 1024 × 1024 ograniczenie chropowatości lub metalicznej tekstury mapy do 512 × 512 może być możliwe przy minimalnym wpływie na jakość zdjęcia. Sprawdź wpływ wszystkich takich eksperymentów związanych ze zmianą rozmiaru, aby mieć pewność, że nie spowodują one negatywnego wpływu na pożądany poziom jakości.

Użyj odpowiedniej przestrzeni kolorów

Wiele pakietów oprogramowania używanych do tworzenia tekstur działa i eksportuje je z wykorzystaniem przestrzeni kolorów sRGB. Rozproszone tekstury, które są przetwarzane jako kolory, mogą wykorzystywać przestrzeń kolorów sRGB. Tekstury, które nie są przetwarzane jako kolory, takie jak metaliczne, chropowatość czy mapy normalne, nie powinny być eksportowane do przestrzeni kolorów sRGB.

Ustawienia tekstur silnika gry zawierają parametr określający, czy tekstura wykorzystuje przestrzeń kolorów sRGB.

Ustawienia tekstur sRGB w Unity i Unreal Engine 4
Rysunek 7. Ustawienia tekstur sRGB w środowiskach Unity (po lewej) i Unreal Engine 4 (po prawej).

Dane pikselowe takich tekstur nie są używane jako dane o kolorach, więc użycie przestrzeni kolorów sRGB spowoduje uzyskanie nieprawidłowych efektów wizualnych.

Renderowanie metalowego człowieka o chropowatości w przestrzeni kolorów liniowych i sRGB
Rysunek 8. Mapa metaliczna liniowa (inna niż sRGB) (po lewej) i metaliczna mapa sRGB z chropowatością (po prawej). Odbicia po prawej stronie wyglądają na nieprawidłowe.

Użyj kompresji tekstur

Kompresja tekstur to algorytm kompresji obrazu stosowany do nieskompresowanych danych pikseli, po której powstaje tekstura, którą można szybko zdekompresować przez sprzęt graficzny podczas renderowania. Efektywne zastosowanie kompresji tekstur może zmniejszyć użycie pamięci i zwiększyć wydajność przy minimalnym wpływie na jakość obrazu. Na Androidzie są najczęściej stosowane 3 algorytmy kompresji tekstur: ETC1, ETC2 i ASTC. W przypadku nowoczesnych gier ASTC jest zwykle najlepszą opcją podstawową, a ETC2 jest opcją zastępczą, jeśli gra jest kierowana na urządzenia, które nie obsługują ASTC.

ETC1

Usługa ETC1 jest obsługiwana przez wszystkie urządzenia z Androidem. ETC1 obsługuje tylko tryb 4-bitowy na piksel dla danych kolorów RGB. ETC1 nie obsługuje kanałów alfa. Wiele silników gier, które obsługują ETC1, zezwala na oznaczanie drugiej tekstury ETC1 do reprezentowania danych kanału alfa.

ETC2

ETC2 jest obsługiwane przez ponad 90% aktywnych urządzeń z Androidem. Bardzo stare urządzenia, które nie obsługują interfejsu OpenGL ES 3.0 API, nie mogą używać ETC2. W porównaniu z ETC1 ETC2 dodaje:

  • Obsługa kanałów alfa – zarówno 8-bitowy, jak i jednobitowy – „przebijanie”
  • Wersje sRGB tekstur RGB i RGBA
  • 1 i 2 kanały, R11 i RG11, tekstury

ASTC

ASTC jest obsługiwane przez ponad 75% aktywnych urządzeń z Androidem. ASTC ma konfigurowalne rozmiary bloków kompresji, co daje szczegółową kontrolę, aby zrównoważyć współczynnik kompresji z jakością obrazu danej tekstury. ASTC często jest w stanie uzyskać najlepszą jakość przy takim samym rozmiarze pamięci jak ETC2 lub podobną ilość przy mniejszym rozmiarze pamięci niż ETC2.

Wizualne porównanie formatów kompresji tekstur korzystających z tego samego obrazu źródłowego
Rysunek 9. Porównanie obrazów: nieskompresowanych (po lewej, o rozmiarze 17 MB), skompresowanych za pomocą ETC1 (w rozmiarze pośrodku, 3 MB), skompresowanych za pomocą ASTC (po prawej, o rozmiarze 2,5 MB).

Prędkość kompresji tekstur

Kompresja tekstur może zająć dużo czasu, jeśli gra ma dużo tekstur. Zarówno ETC, jak i ASTC mają ustawienia jakości kompresji do wyboru. Ustawienia wyższej jakości wymagają więcej czasu na kompresję. W trakcie programowania możesz obniżyć poziom jakości, aby skrócić czas kompresji, i poprawić poziom jakości przed utworzeniem ważnych kompilacji.

Kompresja tekstur w silnikach gier

Jeśli używasz silnika gry, być może trzeba będzie wybrać format kompresji tekstur (ETC lub ASTC) na poziomie projektu. Obsługa wielu formatów kompresji i zapewnienie maksymalnej zgodności może wymagać dodatkowych nakładów pracy. Funkcja kierowania na format kompresji tekstur w ramach Google Play Asset Delivery może pomóc w uwzględnieniu wielu formatów w grze i zapewnić jej optymalny format w momencie instalacji.

Wyodrębnij promienie UV

Dbaj, by wyspa UV była jak najprostsza. Pomaga to w ulepszaniu tekstury w następujący sposób:

  • Opakowanie wysp UV jest łatwiejsze, a tym samym mniej marnowanej przestrzeni.
  • Proste promienie UV zmniejszają „efekt schodów” na teksturach.
  • Dobre wypełnienie UV zapewnia optymalną rozdzielczość tekstury.
  • Lepsza jakość tekstur, nawet jeśli promienie UV są nieco zniekształcone podczas prostowania.
Niezoptymalizowana wyspa UV i zoptymalizowana wyspa UV
Rysunek 10. Niezoptymalizowana wyspa UV (po lewej) i wyprostowana/nieopakowana wyspa UV (po prawej).

Widoczne połączenia tekstur na modelu wyglądają źle. Postaraj się umieścić szwy UV w mniej widocznych miejscach. Aby tworzyć lepsze, normalne mapy, podziel wyspę UV tam, gdzie krawędzie są ostre, i zostaw trochę pustej przestrzeni wokół wyspy.

Unikaj niedostrzegalnych szczegółów

Tworząc grafikę, nie dodawaj szczegółów, które są niewidoczne, zwłaszcza w grach przeznaczonych na urządzenia z mniejszymi ekranami. Uzyskanie bardzo szczegółowej tekstury 4096 x 4096 zmarnuje się na model krzesła, który jest słabo widoczny w rogu pomieszczenia. W niektórych przypadkach może być konieczne wyostrzenie krawędzi (dodanie dodatkowych podświetleń) i cieniowanie, aby poprawić postrzeganie kształtu.

Na modelu renderowanym w oddali widać małą teksturę.
Rysunek 11. Niewielka tekstura o wymiarach 256 x 256 pozbawiona nadmiernej ilości szczegółów została zastosowana na modelu żołnierza renderowanym z daleka.

Szczegóły dotyczące pieczenia

Urządzenia mobilne mają mniejsze ekrany i mniej potężny sprzęt graficzny niż prywatne komputery i konsole do gier. Zamiast obliczać efekty takie jak przesłonięcie otoczenia lub podświetlenie zwierciadłowe w czasie działania, w miarę możliwości rozważ ich wypalenie w formie rozproszonej tekstury. Zwiększa to wydajność i zapewnia widoczność szczegółów.

Wypieki i efekty otoczenia w postaci rozproszonej tekstury
Rysunek 12. Rozświetlenia i przesłonięcie otoczenia ułożone w teksturę rozproszoną (po lewej) i wyrenderowane w grze (po prawej).

Użyj koloryzacji

Jeśli masz możliwość tworzenia niestandardowych programów do cieniowania i masz sieci typu mesh o podobnym lub jednolitym schemacie kolorów, rozważ zastosowanie barwników na odpowiednich siatkach. W przypadku barwienia kolorów używana jest tekstura w skali szarości, która zajmuje mniej pamięci niż tekstura RGB. Kolory siatki są stosowane przez cienia. Alternatywną metodą barwienia jest użycie maski RGB i nałożenie tekstury na podstawie zakresu kolorów maski.

Tekstura w skali szarości zabarwiona w czasie działania.
Rysunek 13. Tekstura w skali szarości (po lewej) w czasie działania dla modelu filarowego (po prawej).

Pakowanie kanałów tekstur

Renderując materiały z wieloma teksturami, szukaj możliwości połączenia tekstur, które korzystają tylko z jednego kanału kolorów, w jedną teksturę wykorzystującą wszystkie 3 kanały kolorów. Zmniejsza to wykorzystanie pamięci i liczbę operacji próbek tekstur wykonywanych przez cieniowanie fragmentów.

Trzy jednokanałowe tekstury połączone w jedną wielokanałową teksturę
Rysunek 14. 3 jednokanałowe tekstury (po lewej) są połączone w jedną wielokanałową teksturę (po prawej). Dane dotyczące przesłonięcia otoczenia są przypisywane do koloru czerwonego, chropowatości/wygładzania koloru zielonego, a metalicznej mapy do niebieskiego.

Podczas pakowania przypisz najbardziej szczegółowe dane do zielonego kanału. Ludzkie oko jest bardziej wyczulone na zieleń, dlatego sprzęt graficznych zwykle przypisuje więcej bitów do kanału zielonego. Na przykład mapa chropowatości/wygładzenia zwykle ma więcej szczegółów niż mapa metaliczna i lepiej ją przypisać do kanału zielonego.

W przypadku materiałów, które używają kanału alfa, jeśli używasz tylko 2 kanałów w upakowanej teksturze, rozważ umieszczenie danych kanału alfa w zapakowanej teksturze zamiast tekstury rozproszonej. W zależności od formatu rozproszonej tekstury może to pomóc zmniejszyć jej rozmiar lub poprawić jakość obrazu przez pominięcie danych o kanale alfa.

Kanał alfa zgrupowany w inną teksturę
Rysunek 15. Mapa nieprzezroczystości kanału alfa jest uporządkowana w teksturę razem z mapą chropowatości/gładkości oraz metaliczną mapą.

Upewnij się, że spakowane tekstury mają liniową przestrzeń kolorów RGB, a nie sRGB.

Twórz zwykłe mapy

Mapowanie normalne to technika, która nadaje modelowi 3D wygląd szczegółów bez używania dodatkowej geometrii. Takie cechy jak zagięcia czy śruby, które mogą wymagać do modelowania wielu trójkątów, można symulować na zwykłej mapie. Standardowe mapowanie może nie być odpowiednie w zależności od stylu grafiki i kierunku gry.

Model renderowany z normalną mapą i bez niej
Rysunek 16. Model wyrenderowany bez zwykłej mapy (po lewej), a także z tym samym modelem wyrenderowanym z normalną mapą (w środku) i zwykłą teksturą mapy (po prawej).

Normalne mapy wiążą się z pewnymi kosztami wydajności, więc należy ich używać z umiarem na słabszych urządzeniach. Mapa zwykła wymaga dodatkowej tekstury, co skutkuje dodatkowym próbkowaniem tekstur i obliczeniami cieniowania fragmentów.

Normalne sprawdzone metody dotyczące map

Oto kilka sprawdzonych metod zwykłego tworzenia map:

Użyj klatki

Klatka to większa (wysunięta) wersja modelu z niskimi wielokątami. Aby dobrze działać podczas normalnego pieczenia mapy, musi obejmować model wysokiego wielokąta. Klatka pozwala ograniczyć odległość od rzutu raycasta podczas normalnego pieczenia mapy oraz uniknąć problemów z rozdzielonymi normalnymi połączeniami na normalnej mapie.

Klatka otaczająca niską siatkę wielokątną
Rysunek 17. Klatka otaczająca niską siatkę wielokątną.
Model wyrenderowany za pomocą zwykłej mapy z klatką i bez niej
Rysunek 18. Renderowanie modelu za pomocą zwykłej mapy wygenerowanej z klatką (po lewej) w porównaniu z modelem wyrenderowanym na podstawie zwykłej mapy wygenerowanej bez klatki (po prawej).

Wypal dopasowanie według nazwy sieci typu mesh

Jeśli Twoje oprogramowanie do pieczenia obsługuje tę funkcję, upiecz dopasowywanie na podstawie nazwy sieci typu mesh. Ta funkcja zmniejsza problem z nieprawidłowym odwzorowaniem normalnej mapy. Gdy obiekty znajdują się zbyt blisko siebie, mogą nieoczekiwanie rzutować swoją normalną mapę na niewłaściwą płaszczyznę. Dopasowanie nazwy siatki daje pewność, że pieczenie odbywa się tylko na właściwej powierzchni. Więcej informacji o tej funkcji w Substance Painter znajdziesz na tej stronie. Więcej informacji na temat tej funkcji znajdziesz na tej stronie.

Rozbicie siatki

Jeśli podczas pieczenia nie możesz znaleźć sieci typu mesh, możesz jej eksplodować. Rozbicie siatki powoduje odsunięcie części od siebie, dzięki czemu zwykła mapa nie wyświetli się na niewłaściwej powierzchni. Jeśli gotujesz pod kątem przesłoniętego otoczenia, konieczne może być pieczenie osobno z użyciem siatki, która nie jest wybuchowa.

Rozbita siatka przy normalnym pieczeniu map
Rysunek 19. Rozbita siatka przy normalnym pieczeniu map

Minimalizuj szwy

Ciągłe nakładanie się promieni UV na twarde krawędzie powoduje widoczne szwy, a udzielenie promieni UV na twarde krawędzie w celu zminimalizowania tego efektu. Przy ustawianiu grup wygładzania zalecamy, aby kąt był mniejszy niż 90 stopni. Złącza UV muszą mieć inną grupę wygładzającą na trójkątach.