Jak udělat LOD pro tisíce animovaných postav v Unity
Návod na LOD pro dav v Unity s vertex animation textures: proč rozhodují vrcholy, ne trojúhelníky, LOD jako nová síť a výběr úrovně po entitách.

LOD pro tisíce animovaných postav v Unity stavte podle počtu vrcholů, ne trojúhelníků: u vertex animation textures se animace počítá na každý vrchol. Nižší úrovně připravte ručně, vrcholy nejnižší úrovně připojte k povrchu originálu a úroveň vybírejte pro každou postavu zvlášť. V naší tower defense hře pro PC to při 3 000 nepřátel zvýšilo FPS při záběru do davu z 62 na 120.
Postup se týká her, kde se na obrazovce pohybují tisíce postav najednou, tedy tower defense, strategií a survival her. Naše hra je postavená v Unity s ECS a najdete ji v referencích. LOD znamená level of detail: vzdálená postava se kreslí z jednodušší sítě. Obrázky jsou skutečné sítě našeho nepřítele kostlivce, ne záběry ze hry.
Proč generovaný LOD davu nepomůže
Unity umí úrovně LOD vygenerovat při importu modelu (funkce Mesh LOD). Pro tisíce postav to má dva problémy.
První je vzhled. Automatické zjednodušení trhalo tenké končetiny a rozbíjelo UV, tedy mapování textury na síť.
Druhý je cena animace. Standardní kosterní animace jsou pro tisíce entit příliš drahé, proto se místo nich používají vertex animation textures (VAT). VAT je textura, kde každý sloupec patří jednomu vrcholu a každý řádek jednomu snímku animace. Shader si polohu vrcholu přečte z textury, takže cena animace závisí na počtu čtených vrcholů, a to i při kreslení stínů.
Horní hranici ukazuje test s vynucenou generovanou úrovní na všech postavách (Unity vygeneruje i úrovně 3 a 4, build, 1080p, 3 000 nepřátel, stíny zapnuté):
| Vynucená úroveň | Trojúhelníky | FPS |
|---|---|---|
| LOD 0 | 11 milionů | 72 |
| LOD 1 | 6 milionů | 96 |
| LOD 2 | 3,68 milionu | 120 |
| LOD 4 | 1,43 milionu | 201 |
Prostor pro zrychlení je velký. Je třeba ho získat bez viditelných děr a skoků mezi úrovněmi.
Počítejte vrcholy, ne trojúhelníky
Poloviční počet trojúhelníků sám o sobě nepomůže. LOD s polovinou trojúhelníků a 996 z původních 1 521 vrcholů ušetřil 1,9 ms na snímek, LOD s 217 vrcholy 6,4 ms. U každé úrovně sledujte oba počty.
Vrcholů bývá zbytečně mnoho. Vrchol se zdvojí na každém švu UV, protože jedna poloha pak potřebuje dvě souřadnice textury. Naše modely z AI generátoru měly UV rozsekané na stovky ostrovů: kostlivec měl 1 521 vrcholů, ale jen 608 různých kombinací polohy a normály.
Krok 1: Snižte počet vrcholů v LOD 0
První úspora nestojí žádný detail. Spojte vrcholy se shodnou polohou a podobnou normálou (rozdíl do 25°), rozbalte UV znovu se švy jen na ostrých hranách (nad 70°) a texturu přepočítejte z původní po trojúhelnících. Kostlivec klesl z 1 521 na 1 090 vrcholů, u ostatních typů nepřátel to bylo o 19 až 29 % méně, při stejném tvaru.
Do VAT pak zapisujte jen sloupce vrcholů, které některá úroveň skutečně používá. Ušetřilo to 40 až 60 % paměti animací.
Krok 2: LOD 1 ze zjednodušení se sdílenou texturou
LOD 1 je zjednodušený LOD 0 na přibližně 52 % trojúhelníků. Zjednodušujte po kouscích (každá kombinace kosti a souvislé části sítě) a vrcholy na hranicích kousků zamkněte. Hlavě dejte větší rozpočet, protože silueta hlavy je to, co oko v davu rozezná.
Důležité je ponechat texturu LOD 0. Úroveň s vlastní texturou nebo jiným tvarem je při přechodu vidět i při podobné siluetě.
Pod zhruba 50 % trojúhelníků zjednodušení z existujících vrcholů trhá tenké části a samostatné kousky. Níž je třeba jít jinak.

Krok 3: LOD 2 jako nová síť připojená k originálu
Nejnižší úroveň je nová uzavřená síť. Originálu přidejte vrstvu tloušťky, proveďte voxel remesh a zjednodušte na cílový počet (u nás 200 až 460 trojúhelníků podle typu nepřítele). Výslednou síť obalte na povrch originálu a UV udělejte automaticky. Texturu zapečte z originálu ve stejné hustotě jako LOD 0, aby seděly i mipmapy.
Nová síť nemá váhy animace. Každý její vrchol proto připojte k nejbližšímu trojúhelníku originálu. Uložte si tři sloupce toho trojúhelníku a barycentrické váhy (podíly, které určují polohu bodu v trojúhelníku).

Sloupec připojeného vrcholu ve VAT je vážený součet poloh a normál těch tří vrcholů v každém snímku. Shader nic neřeší, připojený vrchol je obyčejný další sloupec.
pro každý snímek f:
VAT[připojený, f] = w0 * VAT[a, f] + w1 * VAT[b, f] + w2 * VAT[c, f]
Krok 4: Díry kontrolujte strojově
Obrázky z modelovacího nástroje díry spolehlivě neukážou. Kontrola stačí jednoduchá: vykreslete originál a kandidáta z 11 směrů v rozlišení 120 px a porovnejte siluety.
Za díru počítejte pixely originálu uvnitř obrysu kandidáta, které kandidát nepokryje, a pixely kandidáta více než 2 px mimo obrys originálu. U nás je limit 1 % děr a 4 až 6 % ztráty. Kontrola musí respektovat odstraňování zadních stěn podle materiálu. Limity jsme nastavili podle toho, kde byly přechody ve hře okem vidět.
Krok 5: Vybírejte úroveň pro každou postavu zvlášť
Přepínání úrovně pro celou mapu najednou je vidět. Když vybíráte po entitách, přechody se rozloží a v davu zaniknou.


Upozornění k verzi: dokumentace Unity 6.2 uvádí, že Entities Graphics vždy používá LOD 0. Výběr po entitách podle vzorce níže používáme v Unity 6.6, před nasazením si ověřte chování vaší verze:
LOD = log2(d * C / D) * sklon + posun
C = prah * 2 * tan(fov / 2) / vyska_obrazu
Tady je d vzdálenost od kamery a D průměr světových hranic entity. Sklon a posun zvolte tak, aby úroveň 1 začínala na 93,3 a úroveň 2 na 167,9 metru (kamera s fov 30° a 1440 px). Globální práh LOD nastavte na výšku obrazu / 1440, potom vzdálenosti nezávisí na rozlišení.
Dvě chyby, na které si dejte pozor:
- Měřítko. Průměr
Dpočítejte ze světových hranic, tedy s měřítkem prefabu. Sítě pro VAT bývají v malých jednotkách a prefab je zvětší 2krát až 4krát. Bez toho vám hra celou dobu kreslí LOD 0 a nic nehlásí. Správnost ověřte počtem trojúhelníků v běžném režimu oproti vynucenému LOD. Pootočení entity zvětšuje osově zarovnané hranice, proto u nás průměr násobíme koeficientem 1,22. - Bakování. Křivka výběru se zapéká při bakování SubScene a změnu v síti bakování nezachytí. Po její úpravě vynuťte nové bakování SubScene.
Výsledky a limity
Build pro macOS, 2560 × 1440, 3 000 nepřátel, stíny zapnuté, hra zastavená po prohře (animace VAT stále běží, takže měření platí pro grafiku):
| Scéna | Před | Po |
|---|---|---|
| Celá mapa | 90 FPS | 130 FPS |
| Přiblížení do davu | 62 FPS | 120 FPS |
Na Steam Decku (1280 × 800, 8 výpočetních jednotek RDNA 2) je to 75 až 80 FPS na celé mapě. Nejbližší záběr do davu má při vysoké kvalitě stínů 33 FPS, bez stínů 64. Stíny jsou tedy největší zbývající položka: LOD snižuje i jejich cenu, ale vypnutí stále udělá velký skok.
Co LOD neřeší: kontrola děr běží v T-póze, takže natažení sítě v extrémních pózách neodhalí. Jeden typ nepřítele ještě limit děr v LOD 2 překračuje. Výpočet pohybu hordy LOD neovlivní, ten řeší článek o navigaci hordy v Unity DOTS a reakce na výbuchy fake ragdoll.
Potřebujete pomoct s výkonem hry v Unity nebo simulací davu? Napište nám.


