Az elmúlt 2,5 hónap során többek között ismét előkerült a q3bsp (bezier, nosztalgia stb.) olyannyira, hogy "natív" támogatást kapott az enginemben (importáláskor konverzió nélkül az eredeti fileből készül jelenet). Ehhez azonban a q3bsp renderelésének mélyére kellett ásnom a Q3 forrásának felhasználásával (nem elhanyagolható tényező, hogy a kliens-szerver felépítés miatt nagyon nehéz feltérképezni a működését).
A formátum jellemzője, hogy a jelenet geometriáját (nagyon) szétdarabolva tárolja, amiből következik, hogy (nagyon) nagy mennyiségű drawcall szükséges annak kirajzolásához.
Ezenkívül nem tárol és nem használ portálokat frustum vágáshoz csak és kizárólag PVS-t. Mindezekből következik, hogy a nagy méretű / bonyolult, egybenyíló térrészek gyenge pontjai a formátumnak.
Erre valószínűleg rájöttek a fejlesztők és felhasználtak hozzá egy (nem túl szépen megvalósított) megoldást egy "második PVS-t".
Ez a 2. PVS egy másik térfelosztást használ (cluster-ek helyett area-kat) és félig-meddig dinamikus. A működése egyszerre izgalmas és hack-szagú:
- az area-k összeköttetését / láthatóságát tárolja egy mátrix, amely a 2. PVS alapja
- ajtót "tartalmazó" nyílásokban kell elhelyezni egy ún. areaportal-t, amelynek a bounding boxa bele kell lógjon egy kicsit két (egymással szomszédos) area-ba - ha esetleg többe lóg bele azt a Q3 engine az alábbi "Object %i touching 3 areas at %f %f %f" üzenettel jelzi
- amikor az ajtó kinyílik vagy bezárul, akkor az adott areaportal a hozzá kapcsolódó két area indexe alapján, a mátrixot módosítja egy flood algoritmussal
A renderelés annyiban módosul, hogy nemcsak a kamera clusterét, hanem area-ját is fel kell használni. Amikor egy adott clustert renderelünk akkor a 2. PVS mátrixából megnézzük, hogy a cluster látható-e a kamera area-jából.
Végül ahhoz, hogy ezeket kezelni is tudjam szükség volt a scriptrendszer bevonására. Ez szerencsére nem okozott különösebb problémát, mert az ajtók kezelése eddig is scripteken keresztül történt így mindössze két sort kellett hozzáadnom a megfelelő scripthez.
A másik kihívás a drawcallok számának (további) csökkentése volt, amelyet a geometria összevonásával lehetett elérni. Mivel sajnos ezt nem lehet megtenni betöltéskor mivel több cluster használhatja ugyanazokat a geometriákat run-time (!) kell ezt a problémát megoldani.
Az alapszintű megoldás szerencsére egyszerű:
- egybemásolni a jelenet összes geometriáját betöltéskor
- rendereléskor pedig a látható geometriák index buffereit kell összevonni és azzal renderelni.
Az ördög azonban a részletekben rejlik:
- mivel ES 2.0 a célplatform, ezért figyelni kell, hogy az összevont geometriában a vertexek száma nem lehet több, mint 65535. Amennyiben ezt meghaladjuk több vertex buffert kell használni.
- összevonáskor figyelembe kell venni nemcsak a materialokat, hanem a lightmapeket is
- az index buffereket VBO-zni kell, mert a vertexek is VBO-ban vannak tárolva
- most jön a legjobb: bizonyos ES implementációk nem szeretik (lezuhan a teljesítmény 60 -> 1 fps) ha egy framen belül több VBO update van ezért az összevont index buffereket is össze kell vonni egy nagy bufferbe
- a VBO update-nél figyelni kell az ún. buffer orphanage-re ill. érdemes használni a mapbuffer extension-t
Mindezek segítségével elértem, hogy Tegra 3-on (szerintem a jelenleg játékra ajánlott minimális konfig) interaktív framerate-tel fut.
Ezeken kívül még
- a q3bsp-ben tárolt árnyalási adatokat is át tudtam alakítani az engine-m igényeihez vagyis az eredeti lightgrid adatokat lightprobe-szerűen használom fel
- betöltöm az entityk nagy részét
- navmesh felhasználásával az AI is működésre bírható
- nemcsak a q3bsp formátumot támogatom, hanem rbsp-t (Raven BSP, SW:JK2 + JA használja)
- 5 (!) évvel ezelőtt már készült a q3bsp-ről egy poszt
Ha esetleg valakinek hiányozna ehhez demó, akkor szívesen feltöltöm.
A végén pedig következzen egy SW (Coruscant) kép:
és egy ST (Voyager híd) kép: