LOD készítése több ezer animált karakterhez Unityben
Útmutató tömeg LOD-hoz Unityben vertex animation textures használatával: miért a csúcsok számítanak, LOD új hálóként és entitásonkénti kiválasztás.

A több ezer animált karakter LOD-ját Unityben a csúcsok száma alapján építse fel, ne a háromszögek szerint: vertex animation textures esetén az animációt csúcsonként kell kiszámítani. Az alsóbb szinteket készítse el kézzel, a legalsó szint csúcsait kösse az eredeti felületéhez, a szintet pedig karakterenként válassza ki. PC-s tower defense játékunkban ez 3 000 ellenfélnél a tömegbe közelítve 62-ről 120-ra emelte az FPS-t.
Az eljárás azokra a játékokra vonatkozik, ahol egyszerre több ezer karakter mozog a képernyőn: tower defense, stratégiai és survival játékokra. A miénk Unityben, ECS-sel készül, és a referenciák között található. A LOD a level of detail rövidítése: a távoli karaktert egyszerűbb hálóból rajzoljuk. A képek csontváz ellenfelünk valódi hálóit mutatják, nem játékbeli felvételek.
Miért nem segít a generált LOD egy tömegnél
A Unity a modell importálásakor képes LOD szinteket generálni (a Mesh LOD funkció). Több ezer karakternél ennek két gondja van.
Az első a kinézet. Az automatikus egyszerűsítés felszakította a vékony végtagokat és elrontotta az UV-t, vagyis a textúra leképezését a hálóra.
A második az animáció ára. A hagyományos csontvázas animáció több ezer entitásnál túl drága, ezért vertex animation textures (VAT) kerül a helyére. A VAT olyan textúra, amelyben minden oszlop egy csúcshoz, minden sor egy animációs képkockához tartozik. A shader a textúrából olvassa ki a csúcs helyzetét, így az animáció ára a kiolvasott csúcsok számától függ, az árnyékok rajzolásakor is.
A plafont egy teszt mutatja, ahol minden karakterre egy generált szintet kényszerítettünk (a Unity a 3. és 4. szintet is előállítja, build, 1080p, 3 000 ellenfél, bekapcsolt árnyékok):
| Kényszerített szint | Háromszögek | FPS |
|---|---|---|
| LOD 0 | 11 millió | 72 |
| LOD 1 | 6 millió | 96 |
| LOD 2 | 3,68 millió | 120 |
| LOD 4 | 1,43 millió | 201 |
A gyorsításra bőven van tér. Ezt látható lyukak és a szintek közti ugrások nélkül kell kihasználni.
A csúcsokat számolja, ne a háromszögeket
A fele annyi háromszög önmagában nem segít. Egy LOD fele annyi háromszöggel és az eredeti 1 521 csúcsból 996-tal 1,9 ms-ot takarított meg képkockánként, egy 217 csúcsos LOD 6,4 ms-ot. Minden szintnél kövesse mindkét számot.
Gyakran fölöslegesen sok a csúcs. Minden UV-varratnál megkettőződik a csúcs, mert egy pozícióhoz ilyenkor két textúrakoordináta tartozik. Az AI-generátorból származó modelljeink UV-ja több száz szigetre volt vágva: a csontváznak 1 521 csúcsa volt, de csak 608 különböző pozíció-normál párosa.
1. lépés: Csökkentse a csúcsokat a LOD 0-ban
Az első megtakarítás nem jár részletvesztéssel. Egyesítse az azonos pozíciójú és hasonló normálú csúcsokat (25° eltérésig), bontsa ki újra az UV-t csak az éles éleken (70° felett) varrattal, és a textúrát számolja át a régiből háromszögenként. A csontváz 1 521-ről 1 090 csúcsra csökkent, a többi ellenféltípus 19-29 %-kal, változatlan alakkal.
Ezután csak azoknak a csúcsoknak az oszlopait írja a VAT-ba, amelyeket valamelyik szint ténylegesen használ. Ez az animációs memória 40-60 %-át spórolta meg.
2. lépés: LOD 1 egyszerűsítéssel, közös textúrával
A LOD 1 a háromszögek körülbelül 52 %-ára egyszerűsített LOD 0. Darabonként egyszerűsítsen (a csont és a háló összefüggő részének minden párosítása), és rögzítse a darabok határán lévő csúcsokat. A fejnek adjon nagyobb keretet, mert a fej sziluettjét ismeri fel a szem a tömegben.
Fontos megtartani a LOD 0 textúráját. Az önálló textúrájú vagy más alakú szint átmenetkor hasonló sziluett mellett is látszik.
A háromszögek nagyjából 50 %-a alatt a meglévő csúcsokból való egyszerűsítés felszakítja a vékony részeket és a különálló darabokat. Lejjebb másképp kell haladni.

3. lépés: LOD 2 az eredetihez kötött új hálóként
A legalsó szint új, zárt háló. Vastagítsa meg az eredetit egy réteggel, futtasson voxel remesht, és egyszerűsítsen a célszámra (nálunk ellenféltípustól függően 200-460 háromszög). Az eredményt húzza rá az eredeti felületére, az UV-t pedig készítse automatikusan. A textúrát az eredetiből süsse a LOD 0-val azonos sűrűségben, hogy a mipmapek is egyezzenek.
Az új hálónak nincsenek animációs súlyai. Ezért minden csúcsát kösse az eredeti legközelebbi háromszögéhez. Mentse el a háromszög három oszlopát és a baricentrikus súlyokat (az arányokat, amelyek meghatározzák a pont helyét a háromszögön belül).

A kötött csúcs VAT-oszlopa minden képkockában a három csúcs pozíciójának és normáljának súlyozott összege. A shadernek semmi különöset nem kell tennie, a kötött csúcs csak egy újabb oszlop.
minden f képkockára:
VAT[kötött, f] = w0 * VAT[a, f] + w1 * VAT[b, f] + w2 * VAT[c, f]
4. lépés: Géppel ellenőrizze a lyukakat
A modellező eszköz képei nem mutatják megbízhatóan a lyukakat. Elég egy egyszerű ellenőrzés: renderelje az eredetit és a jelöltet 11 irányból 120 px-es felbontásban, és hasonlítsa össze a sziluetteket.
Lyuknak számítsanak az eredeti pixelei a jelölt körvonalán belül, amelyeket a jelölt nem fed le, valamint a jelölt pixelei az eredeti körvonalán több mint 2 px-lel kívül. Nálunk a határ 1 % lyuk és 4-6 % veszteség. Az ellenőrzésnek figyelembe kell vennie az anyagtól függő hátlap-eltávolítást. A határokat az alapján állítottuk be, hogy hol látszottak az átmenetek a játékban.
5. lépés: Karakterenként válasszon szintet
Ha az egész térképen egyszerre vált a szint, az látszik. Entitásonkénti kiválasztásnál az átmenetek eloszlanak és eltűnnek a tömegben.


Verziófigyelmeztetés: a Unity 6.2 dokumentációja szerint az Entities Graphics mindig LOD 0-t használ. Az alábbi képlet szerinti entitásonkénti kiválasztást Unity 6.6-ban használjuk, ezért előbb ellenőrizze a saját verziója viselkedését:
LOD = log2(d * C / D) * meredekseg + eltolas
C = kuszob * 2 * tan(fov / 2) / kepmagassag
Itt d a kamerától mért távolság, D pedig az entitás világbeli határainak átmérője. A meredekséget és az eltolást úgy válassza meg, hogy az 1. szint 93,3, a 2. szint 167,9 méternél kezdődjön (30°-os fov és 1440 px-es kamera). A globális LOD-küszöböt állítsa képmagasság / 1440 értékre, így a távolságok nem függenek a felbontástól.
Két hiba, amelyre figyeljen:
- Méretarány. A
Dátmérőt a világbeli határokból számolja, tehát a prefab méretarányával együtt. A VAT-hálók gyakran kis egységekben vannak, a prefab 2-4-szeresére nagyítja őket. Enélkül a játék végig LOD 0-t rajzol, és nem jelez semmit. Ellenőrizze a háromszögek számával normál módban egy kényszerített LOD-hoz képest. Az entitás elforgatása megnöveli a tengelyhez igazított határokat, ezért nálunk az átmérőt 1,22-es szorzóval számoljuk. - Sütés. A kiválasztási görbe a SubScene sütésekor kerül rögzítésre, és a sütés nem veszi észre a háló változását. Módosítás után kényszerítse ki a SubScene újrasütését.
Eredmények és korlátok
macOS build, 2560 × 1440, 3 000 ellenfél, bekapcsolt árnyékok, a játék game over után megállítva (a VAT-animációk továbbra is futnak, így a mérés a grafikára érvényes):
| Jelenet | Előtte | Utána |
|---|---|---|
| Teljes térkép | 90 FPS | 130 FPS |
| Közelítés a tömegbe | 62 FPS | 120 FPS |
A Steam Decken (1280 × 800, 8 RDNA 2 számítási egység) ez 75-80 FPS a teljes térképen. A tömeghez legközelebbi nézet magas árnyékminőséggel 33 FPS, árnyékok nélkül 64. Az árnyékok jelentik tehát a legnagyobb megmaradt költséget: a LOD ezek árát is csökkenti, de a kikapcsolásuk még mindig nagy ugrást ad.
Amit a LOD nem old meg: a lyukellenőrzés T-pózban fut, így nem veszi észre az extrém pózokban fellépő nyúlást. Egy ellenféltípus LOD 2-ben még túllépi a lyukhatárt. A horda mozgásának számítására a LOD nincs hatással, erről a horda navigációja Unity DOTS-ban cikk szól, a robbanásokra adott reakciókról pedig a fake ragdoll.
Segítségre van szüksége Unity-játéka teljesítményével vagy tömegszimulációval kapcsolatban? Írjon nekünk.


