Dlaczego warto stosować podwójne buildy w swojej grze Unity 3D
Kompatybilność tekstur
Jednym z kluczowych powodów jest kompatybilność zasobów. W szczególności wsparcie dla tekstur różni się znacząco pomiędzy Mobile Web (urządzenia Android i iOS) a Desktop Web (macOS, Linux, Windows). Aby lepiej zrozumieć, dlaczego ma to znaczenie, przyjrzyjmy się bliżej danym:
Desktop Browsers | iOS and Android browser | |
RGB Compressed ETC2 | No | Yes |
RGB Crunched ETC | No | Yes |
RGBA Compressed ETC2 | No | Yes |
RGBA Crunched ETC2 | No | Yes |
RGB Compressed DXT1, also known as BC1 | Partial (*) | No |
RGB Crunched DXT1, also known as BC1 | Partial (*) | No |
RGBA Compressed DXT5, also known as BC3 | Partial (*) | No |
RGBA Crunched DXT5, also known as BC3 | Partial (*) | No |
* With linear rendering on web browsers that do not support sRGB DXT, textures are decompressed to RGBA32 at load time.
Formaty DXT1/5 „działają” na urządzeniach mobilnych, ale następuje fallback do nieskompresowanego RGBA, co skutkuje większym zużyciem pamięci RAM i wydłużonym czasem ładowania z powodu konwersji tekstur.
Szczegółowe informacje znajdziesz w dokumentacji Unity: https://docs.unity3d.com/2021.3/Documentation/Manual/class-TextureImporterOverride.html
Optymalizacja zasobów
Oddzielenie buildów umożliwia dostarczenie zoptymalizowanych zasobów dostosowanych do urządzeń mobilnych.
Ekrany mobilne charakteryzują się bardzo dużą gęstością pikseli (dpi – pixels per inch). Oznacza to, że pixel shader na małym wyświetlaczu 5–6 cali wykonuje prawie tyle samo obliczeń, co na pełnym monitorze 2K przy znacznie słabszym mobilnym GPU. Dodatkowo CPU w urządzeniach mobilnych jest znacząco słabsze i często ograniczone do pracy jednordzeniowej.
Tutaj z pomocą przychodzą podwójne buildy, pozwalają one dostarczyć alternatywne zasoby i ustawienia dla urządzeń mobilnych, takie jak:
- Zoptymalizowane shadery i materiały
- Dostosowana jakość cieni
- Uproszczone oświetlenie (np. w pełni wypalone z obsługą tylko 1–2 dynamicznych źródeł światła)
- Modele o zredukowanej liczbie polygonów (modele wysokopoligonowe są trudne do przetwarzania przy ograniczonej liczbie jednostek wierzchołkowych w mobilnych GPU, a dodatkowe detale są zbędne na małych ekranach)
- Uproszczone, przyjazne GPU lub wypalone animacje (istotne dla wszystkich buildów Web; animacje szkieletowe, które nie mogą być w pełni przetwarzane przez GPU, szybko stają się problemem)
Optymalizacja zachowania i kodu
Dyrektywy kompilatora, generowanie kodu i podobne techniki pozwalają dostarczać kod i zachowania specyficzne dla danej platformy, bez wprowadzania kar wydajnościowych ani nadmiernej abstrakcji.
Takie podejście umożliwia:
- Optymalizację metod wprowadzania danych dla różnych urządzeń (dotyk, mysz, kontroler itp.)
- Dostosowanie układu interfejsu (UI) do mniejszych ekranów lub specyficznych metod interakcji
- Zastępowanie lub upraszczanie kosztownych procedur zoptymalizowanymi wersjami
Jak tworzyć podwójne buildy
Tutaj znajdziesz mój przykładowy projekt pokazujący automatyzację buildów, rozdzielenie Mobile/Desktop Web oraz wsparcie dla Dockerizacji:
https://github.com/AndreiMaksimovich/Unity-Build-and-Test-Automation
Oddzielne buildy
Przykład tego podejścia jest dostępny w repozytorium wymienionym powyżej.
Główna idea polega na generowaniu oddzielnych buildów dla każdego wymaganego typu platformy – takich jak Mobile Web, Desktop Web, Tablety mobilne (ekrany dotykowe 9 cali i większe) – a następnie automatycznym przekierowaniu gracza do odpowiedniego builda.
Scalony build
Idea stojąca za tą metodą polega na połączeniu wielu buildów w jeden. Dzięki temu możemy programistycznie wybrać różne źródła danych, kodu i zasobów jeszcze przed inicjalizacją Unity playera. Przyjrzyjmy się, jak można to zrealizować.
Przyjrzyjmy się domyślnemu szablonowi Unity Web w Unity 6.2 – a dokładniej plikowi index.html
w liniach 61–81:
var buildUrl = "Build";
var loaderUrl = buildUrl + "/{{{ LOADER_FILENAME }}}";
var config = {
arguments: [],
dataUrl: buildUrl + "/{{{ DATA_FILENAME }}}",
frameworkUrl: buildUrl + "/{{{ FRAMEWORK_FILENAME }}}",
#if USE_THREADS
workerUrl: buildUrl + "/{{{ WORKER_FILENAME }}}",
#endif
#if USE_WASM
codeUrl: buildUrl + "/{{{ CODE_FILENAME }}}",
#endif
#if SYMBOLS_FILENAME
symbolsUrl: buildUrl + "/{{{ SYMBOLS_FILENAME }}}",
#endif
streamingAssetsUrl: "StreamingAssets",
companyName: {{{ JSON.stringify(COMPANY_NAME) }}},
productName: {{{ JSON.stringify(PRODUCT_NAME) }}},
productVersion: {{{ JSON.stringify(PRODUCT_VERSION) }}},
showBanner: unityShowBanner,
};
To, na co tutaj patrzymy, to konfiguracja inicjalizacji instancji Unity. Kluczową kwestią jest to, że konfiguracja ta jest skryptowalna – co oznacza, że możemy dynamicznie zmieniać adresy URL pliku Data, pliku Wasm oraz Streaming Assets „w locie”, skutecznie przełączając zarówno bazę kodu, jak i zasoby.
Teraz przyjrzyjmy się plikowi index.html
w buildzie webowym:
var buildUrl = "Build";
var loaderUrl = buildUrl + "/Build.loader.js";
var config = {
arguments: [],
dataUrl: buildUrl + "/Build.data.gz",
frameworkUrl: buildUrl + "/Build.framework.js.gz",
codeUrl: buildUrl + "/Build.wasm.gz",
streamingAssetsUrl: "StreamingAssets",
companyName: "DefaultCompany",
productName: "Demo",
productVersion: "1.0.2",
showBanner: unityShowBanner,
};
Można to łatwo zmodyfikować do czegoś takiego:
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
var buildUrl = "Build";
var loaderUrl = buildUrl + "/Build.loader.js";
var config = {
arguments: [],
dataUrl: buildUrl + (isMobile ? "/Build.Mobile.data.gz" : "/Build.data.gz"),
frameworkUrl: buildUrl + "/Build.framework.js.gz",
codeUrl: buildUrl + (isMobile ? "/Build.Mobile.wasm.gz" : "/Build.wasm.gz"),
streamingAssetsUrl: (isMobile ? "StreamingAssets.Mobile" : "StreamingAssets"),
companyName: "DefaultCompany",
productName: "Demo",
productVersion: "1.0.2",
showBanner: unityShowBanner,
};
To zapewnia prosty sposób na rozróżnienie i dostarczenie osobnego kodu oraz zasobów dla Mobile i Desktop.
Jak można to zautomatyzować:
- Utwórz niestandardowy szablon, w którym
dataUrl
,codeUrl
istreamingAssetsUrl
zostaną zastąpione tak, jak pokazano powyżej. - Użyj tego szablonu, aby zbudować projekt osobno dla Mobile i Desktop.
- Połącz buildy w jeden – zasadniczo poprzez skopiowanie plików Data, Wasm i Asset z jednego builda do drugiego oraz zmianę ich nazw tak, aby odpowiadały konfiguracji w szablonie.
Uwaga: To jest uproszczone wyjaśnienie, ale działa i może zostać rozszerzone, aby dopasować się do konkretnych wymagań.