HTML

gondolataim elsősorban játékfejlesztésről

Elsősorban játékfejlesztés magyarul: az enginem fejlesztése során felmerülő problémák, ötletek, tévutak stb dokumentálása, amely számomra és talán mások számára is hasznos lehet később Másodsorban gondolatok szavakban...

Kapcsolat:
aalberik 'at' gmail 'dot' com

Haletető

Galéria

Címkék

Összes

Linkblog

Naptár

december 2024
Hét Ked Sze Csü Pén Szo Vas
<<  < Archív
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31

Szabadság - első nap

2010.09.01. 00:59 :: syam

Miután sikeresen aludtam közel 11 órát belevetettem magam az engine-m programozásába.

Cinematic

Elmúlt hétvégén sokat gondolkoztam azon az egyszerű(nek tűnő) feladaton, hogy hogyan lehet a kamerát egy adott pályán "szépen" mozgatni. A "szépen" fogalom elevel kizárja a lineáris interpolációt helyette a natural cubic spline-t használó interpolációt építettem be. Ehhez is mindössze a kulcspontokat kell megadni a szükséges együtthatókat az algoritmus kiszámítja.
Ezt felhasználva a script nyelvemet kiegészítettem kamera animálási és néhány post-process utasításokkal így elvileg bármikor indítható ingame "videó".

Játék logika - tárgykezelés

Aztán felfedeztem a kódban egy még sosem használt kódrészletet -nevezetesen PickObject és ThrowObject - és most már megvan a lehetőség, hogy használjam is.
Az első eljárás megnézi a felvevő szereplő környezetét és ha talál abban egy tárgyat akkor azt magához hozzárendeli és berakja a saját inventory-jába.
A második eljárás egy adott tárgyat kivesz a tulajdonos inventory-jából és elhelyezi a tulajdonos közelében.
Természetesen később ezek finomításra szorulnak, de már működnek:3
 

Dies diem docet...

 

Szólj hozzá!

Címkék: lua postprocess

Egyszerű, de nagyszerű - lens flare

2010.08.26. 22:50 :: syam

Eddig még nem nagyon jutott időm és lehetőségem effektek készítésére, de most végre sikerült megvalósítanom a lens flare-t avagy a lencsecsillanást. 

A jelenség fizikai okai a képrögzítéshez használt lencse fénytörésére vezethető vissza, amely nehezen (vagy nem) szimulálható képszintéziskor azonban a látvány egyszerűen utánozható.

Ehhez mindössze egy adatra van szükségünk: a fényforrás 3D pozíciójára.

Lépések:

  1. Átvisszük a fényforrást a clip space-be (itt a tartomány -w...+w). Ez a művelet egy olyan gluProject, amelyből kihagyjuk a viewport és depth range transzformációt. Ez a művelet mindössze a modelview-projection mátrix és a pozíció beszorzását igényli.
  2. Elvégezzük a (homogén) vágást a közeli (-z) oldalra (azért kell a közeli oldalra ez a fajta vágás, hogy elkerüljük a homogén átfordulást) aztán a homogén osztást. Így átkerül NDC-be (ahol a tartomány -1...+1) a fényforrás és itt is elvégezzük a vágást. Ezekkel a lépésekkel gyakorlatilag egy frustum vágást valósítottunk meg.
  3. A következő lépés opcionális. Ugyanis még egy láthatósági vizsgálatot (occlusion cull) is eszközölhetünk, amelyre többféle módszer létezik. Szinte kínálja magát az occlusion query, de helyette használjunk egy másik módszert.
    3. a. Végezzük el a viewport és a depth range transzformációt.
    3. b. glReadPixels-szel olvassuk ki a megfelelő mélység értéket.
    3. c. Hasonlítsuk össze az általunk használt értékkel. Amennyiben a kiolvasott érték kisebb, mint a miénk akkor takarásban van a fényforrás.
  4. Tehát most már tudjuk, hogy a fényforrás látszik-e vagy sem és azt is tudjuk, hogy az NDC-ben hol helyezkedik el.
  5. Következő lépésben kiszámoljuk a kiegészítő elemek helyzetét. Ilyenkor már 2D-ben számolunk vagyis csak az x és y komponensekre van szükségünk. Szerencsére az NDC origójának x,y síkra vett vetülete a képernyő középpontjával megegyezik így nincs szükségünk eme pont kiszámítására és így a fényforrás levetített pozícióját tekinthetjük egyben egy irányvektornak (FFIV) is. A lens flare járulékos elemei a FFIV mentén fognak elhelyezkedni. Számoljuk ki FFIV hosszát (L) és normalizáljuk (NFFIV). A kiegészítő elemek a NFFIV * L * factor helyre fognak kerülni, ahol a factor egy általunk megadott érték, amely lehet negatív is.
  6. Szerencsére az NDC-ben történő renderelés is egyszerű:
    - a vetítési és modellnézeti mátrixot egységmátrixra kell állítani 
    - az előzőleg kiszámolt pozíciók mind NDC-ben vannak.

Természetesen annyi járulékos elemet jeleníthetünk amennyit szeretnénk, de általában 4-6 darab elég szokott lenni. 
A factor tetszőlegesen variálható elemenként hasonlóan az elemek méretéhez.
Figyeljünk arra, hogy a lens flaret ne additív blendeléssel, hanem alfa blendeléssel rajzoljuk ki és ezt a textúrák készítésekor is vegyük figyelembe!

 

Szólj hozzá!

Címkék: occlusion cull glreadpixels lens flare

A végső megoldás: CSSM

2010.08.18. 11:54 :: syam

A videóim között böngészve bukkantam az alábbi újdonságra: (ismét) egy új shadow map technika, mely (ismét) azt ígéri, hogy üdvösséget hoz a használójának.

A többiekkel ellentétben azonban ez valóban hatásosnak tűnik.

Íme a bemutató videó:

 

 

Sajnos a dokumentáció még nem született meg hozzá és egyelőre D3D alatt implementálták.
A használatához három dolog szükséges:

  • GetOptimalCSSMShaderParams, amely kiszámítja a szükséges vetítési és vezérlő mátrixokat. Ez megtalálható a csomagban dll-ként.
  • Shadow map generáló vertex program.
  • Shadow map felhasználó fragment program. Mindkét program / shader szintén szerepel a csomagban.

Szólj hozzá!

Címkék: shadow map cssm

Én + a gui

2010.08.17. 12:39 :: syam

Több hónapnyi szenvedés végére sikerült pontot tennem elmúlt hétvégén. Az enginem látott már néhány gui-t egy kivételével (guichan.sourceforge.net/) mindegyik saját próbálkozás volt.

Sajnos egy jól használható gui elkészítése nem kevés idő és energia. Ezenkívül szükséges hozzá külső szerkesztési lehetőség script vagy - ami leginkább ajánlott - vizuális eszköz formájában.

Miután ez nagy nehezen világossá vált elkezdtem keresgélni külső segítség után. Érdekes módon nincs túl nagy kínálat. A legtöbb SDK meglehetősen nagy méretű ami számomra nem tűnt szimpatikusnak. Azonban ha speciálisan játékhoz szánt gui-t keresünk kicsit jobbak az esélyek. Léteznek egyéni próbálkozások (egyik igéretes ez volt www.thomasandamy.com/projects/GLO/ ), de sajnos ezek támogatottsága nem a legjobb.

Utolsó próbálkozásom a CEGUI volt. A mérete ennek sem kicsit, de töredéke a "nagy" SDK-knak. A következő kérdéses pont a függőségek voltak, amiből akad néhány. Természetesen a csomag elérhető előre lefordított csomagként is így a függőségekkel nem kellene foglalkozni, de jobban szeretem magamnak lefordítani és csak azt ami nekem szükséges. Így nekiláttam kiválogatni a számomra szükségtelen összetevőket.
Nagyon előnyös tulajdonsága a CEGUI-nak, hogy nagyon praktikus konfiguráló lua scriptet készítettek hozzá.

Ami mindenképp szükséges, hogy használhatóvá tegyük:

  • Freetype.
  • Legalább egy image codec. Lehetőleg ne a beépített TGA legyen, hanem a SILLY, amit kimondottan a CEGUI-hoz fejleszettek ki. Kezeli a JPG, PNG és TGA formátumokat, ami gyakorlatilag mindenhez elég. Az első kettő formátumhoz szükségesek a nekik megfelelő könyvtárak, de általában ezeket a játék engine-k is igénylik.
  • Falagard window renderer.
  • XML parser. Szerencsére a tinyxml verzió beépített így nem kell külön könyvtár hozzá.
  • Renderer. Az OpenGL renderer a glew könyvtárat használja, amelyet bevontak a CEGUI-ba.

Szerencsére a használata sem egetverően bonyolult könnyen rá lehet érezni a stílusára. Könnyen skin-elhető, létezik hozzá vizuális szerkesztő és folyamatosan fejlesztik. Amivel viszonylag meggyűlt a gondom az a setDefaultResourceGroup és a setResourceGroupDirectory volt ti. mindkettőt az inicializáláskor megfelelően be kell állítani. Ezek után viszont adja magát a használat. Annyit talán érdemes még megjegyezni, hogy az események kezelése callback-eken keresztül működik tehát ezt figyelembe véve kell struktúrálni a függvényeinket / osztályainkat.

 

Szólj hozzá!

Címkék: gui cegui

Mipmap generálás alsófokon

2010.07.15. 17:10 :: syam

Néhány apró észrevétel az OpenGL-ben elérhető (textúra) mipmap generálási lehetőségekkel kapcsolatban.

Talán vannak akik emlékeznek a gluBuild2DMipmaps nevű glu függvényre. Szerencsére ma már nagyon ritka, hogy ilyen módon (szoftveresen) szükséges előállítani a mipmap szinteket mivel a mai GPU-k hardveresen képesek ezt megoldani. Ennek azonban két módja lehetséges, amelyekre érdemes odafigyelni.

GL_GENERATE_MIPMAP

Ez a régebbi módszer, amely még a SGI nevéhez fűződik. Használata:

glTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);

glGenerateMipmap

Ez az FBO extension-nel együtt született a registry tanulsága szerint. Elődjétől eltérően ez már függvény és más a működési elve is. Használata:

glGenerateMipmap (GL_TEXTURE_2D);

A működése elve miatt fontos, hogy akkor kell meghívni, amikor a mipmap szinteket le akarjuk gyártani. Mindenképp szükséges a glTexImage.. után (mivel ekkor foglalja le a helyet is a textúra számára)!

Felhasználásukban is különbségek mutatkoznak. Míg az előbbit "statikus" textúrákhoz az utóbbit mindkettőhöz, de leginkább a dinamikus és főleg a render-to-texture textúrákhoz ajánlják - bizonyos források szerint a GL_GENERATE_MIPMAP esetén minden egyes rajzolási hívás után legyártásra kerülnek a mipmap szintek míg a glGenerateMipmap esetén csak akkor amikor szeretnénk. Ezt úgy tehetjük meg, hogy glBindTexture után meghívjuk a glGenerateMipmap-t.

A példákban GL_TEXTURE_2D szerepelt azonban a generálás működik GL_TEXTURE_3D és "GL_TEXTURE_CUBE_MAP" esetén is.

Szerk:
A kettő kvázi kizárja egymást; az első a magasabb GL verziókban deprecated.

Szólj hozzá!

Címkék: texture generete mipmap

Loose octree

2010.07.05. 13:51 :: syam

A következő állomás az engine újratervezésében egy új térfelosztó algoritmus megírása. A BVH, amit eddig használtam mindaddig jó, amíg csak statikus adatokról van szó. Az újraépítése sajnos nem elég gyors különösen nagy jelenet esetén hasonlóan az octree-hez.
Lehetne külön fában tárolni a dinamikus elemeket azonban két fára vizsgálni és karbantartani egyszerre sem megoldás.
Utánajárva a lehetőségeknek bukkantam a loose octree-re (magyarul "lazított" oktális fa), amely dinamikus jelenet tárolásához ideális.
Megjegyzés: a PhysX is tud ilyet használni ha belenézünk az SDK-jába:
NX_PRUNING_OCTREE,    //!< Using a preallocated loose octree
NX_PRUNING_QUADTREE,   //!< Using a preallocated loose quadtree

A neten találtam egy látványos demot (bár ez 2D verzió vagyis a loose quadtree műküdését mutatja be) java-ban, ahol ki lehet próbálni a hagyományos quadtree-t is.

donar.umiacs.umd.edu/quadtree/rectangles/loosequad.html

 

1 komment

Címkék: octree bvh loose octree

Olvasnivaló: mélység vagy szín?

2010.07.04. 12:50 :: syam

Miután pár hete csak az image space occlusion cull-al foglalkozom elértem ahhoz a ponthoz, amikor már az optimalizációs lehetőségeket keresi az ember. Amikor a CPU oldali lehetőségek elfogynak, akkor jön a GPU oldal. Ezek közül a glReadPixels jár az élen tekintve, hogy kb. felezi az fps-t. Vegyünk sorra azt a néhány - mert sajnos nem sok van - extension-t amik ennek gyorsítására lettek kitalálva.

Pixel buffer object

Ez az OpenGL object az aszinkron adatmozgatást (PACK avagy letöltés és UNPACK azaz feltöltés) hivatott megoldani. Az aszinkronitás itt azt jelenti, hogy a glBindBuffer + glReadPixels utasításpár nem blokkolja az alkalmazást, hanem csak elindít egy párhuzamos adatátvitelt egy kliens oldali memóriaterületre. Ennek a címét majd a glMapBuffer utasítással tudjuk lekérdezni, amely - érthető okokból - már egy szinkronizációt is végrehajt. Amennyiben volt elég idő az átvitelre, akkor a szinkronizáció nem jár időveszteséggel ellenkező esetben semmivel nem lesz gyorsabb a mezei glReadPixels hívásnál.
Amennyiben sikerül biztosítanunk az elegendő időt rájövünk, hogy nem mindegy mit és hogyan olvasunk.

  • A PBO-t GL_STREAM_READ-ként lefoglalnunk; a GL_STATIC_READ némileg lassabb.
  • Ha színt akarunk olvasni, akkor csakis GL_BGRA formátumban és GL_UNSIGNED_BYTE típusként tegyük (azonban valószínű más típust is lehet használni még). Ilyenkor jelentős (2x) sebesség növekedést is tapasztalhatunk.
  • Ha mélységet akarunk olvasni, akkor jönnek a meglepetések. Az általam használt nVidia kártyán ugyanis bármit használtam nem tapasztaltam gyorsulást. Tehát GL_DEPTH_COMPONENT mellé kipróbáltam GL_FLOAT-ot, GL_UNSIGNED_INT-et, GL_UNSIGNED_SHORT-ot (bár hardveresen gyorsított és 16 bites depth bufferrel rendelkező PFD nem volt) és a teszt kedvéért GL_UNSIGNED_BYTE-ot.

Így hát jöttek a további próbálkozások...

Packed depth - stencil

Ehhez az szükséges, hogy mélység buffer 24 bites legyen és mellette legyen 8 bites stencil buffer is. Ilyenkor nem GL_DEPTH_COMPONENT-et olvasunk, hanem GL_DEPTH_STENCIL-t GL_UNSIGNED_INT24_8 típusként. Sajnos ez sem segített a helyzeten.

NV copy depth to color

Úgy tűnik hát, hogy a GPU-k nem igazán szeretik a mélység buffer olvasását ellenben a szín bufferét igen. Erre valószínűleg nVidiánál is rájöttek (vagy eleve tudták...) így hát készítettek hozzá egy extension-t.
Megjegyzés: náluk nem ismeretlen ez a megoldás. A Tegra 1 és 2 platform is rossz felbontású mélység bufferrel bír (takarási problémák mindenfelé). Erre kitaláltak egy extension-t, ami "nem-lineáris kódolású"-vá alakítja a mélység buffert és így eltűnnek a problémák.
Az extension nevéből kitalálható a működési elv. Egy glCopyPixels hívással átmásolható a mélység buffer a szín bufferbe (GL_DEPTH_STENCIL_TO_RGBA_NV vagy GL_DEPTH_STENCIL_TO_BGRA_NV). De ez is ugyanolyan feltételek mellett használható, mint a packed depth-stencil (ami szintén az ő nevükhöz fűződik...) valamint a szín buffernek 32 bitesnek kell lennie.


Összegezve

Ha mélység buffert szeretnék olvasni nVidia kártyán akkor az alábbiakat érdemes megtenni.

  1. glCopyPixels(..., GL_DEPTH_STENCIL_TO_BGRA_NV);
  2. glBindBuffer (GL_PIXEL_PACK_BUFFER,...);
  3. glReadPixels (..., GL_BGRA, GL_UNSIGNED_BYTE,..);
  4. glMapBuffer (...)
  5. A lekért adatok elérhetők 24 biten elkódolt 0...1 tartományba eső float-ként.

Gutta cavat lapidem, non vi, sed saepe cadendo...

Szólj hozzá!

Címkék: pixel buffer object glreadpixels

Occlusion cull - hierarchical z-buffer visibility

2010.07.02. 11:27 :: syam

Hosszú idő és sok-sok próbálkozás után úgy látszik megszületett...
Az occlusion cull-ról már írtam korábban, de repetitio est mater studiorum avagy ismétlés a tudás anyja.

Az occlusion cull elve nagyon egyszerű: a renderelésből eldobja azon elemeket, amik az adott látótérben nem látszanának, mert takarásban vannak. Azonban - mint általában - ezt mondani könnyű megoldani viszont nehéz.

Mint a 3D megjelenítésben használt algoritmusok egy részének, ennek is két nagy csoportja van: image space és object space. Általában az object space megoldások CPU igényesebbek így emiatt az image space megoldások az érdekesebbek. Összehasonlításul: árnyékok renderelésénél az object space megoldás a shadow volume az image space pedig a shadow map.

Az occlusion cull image space technikái közül egy 1993-ban publikált tűnt nekem igéretesnek a hierarchical z-buffer visibility.

 Az algoritmus két részből áll.

  • Lerendereljük a lehetséges occludereket egy z-bufferbe majd a z-bufferből ún. z-piramist építünk (minden szint az előző méretének a negyede). Nagyban hasonló ez egy mipmap piramishoz viszont nem átlagolással történik a kicsinyítés, hanem az átlagoláshoz felhasznált négy érték közül a legnagyobb kerül át az alacsonyabb szintre.
  • A megjelenítendő elemeket összevetjük a z-piramissal. Levetítjük az elemet a képernyőre és így a z-piramisra is. Majd a z-piramis azon helyeiről kiolvassuk a mélység értékeket, amelyekre az elem vetült. Amennyiben bármelyik érték nagyobb, mint az elem bármelyik pontja akkor az elem látható.
    A z-piramis hierarchizált voltából következik, hogy nem kell az egész z-buffert végigvizsgálni, hanem alulról (1x1 mérettől) felfelé haladva viszonylag kevés összehasonlítással eldönthető a láthatóság.

A teljesítmény...

Óvatosan kell bánni ezzel az eljárással.

  1. Ha hardveresen rendereljük az occludereket, akkor a z-buffert vissza kell olvasni glReadPixels függvénnyel, ami a leglassabb lépése az eljárásnak. Gyorsítására elméletileg két lehetőség adott: PBO és RBO. Az előbbi valójában tovább lassít, ha nem sikerül kihasználni a visszaolvasási időt (esetleg dupla bufferelni kellene?). Valódi lehetőségnek az RBO tűnik. Idézet a GPGPU programming cikkből:

    Downloading is getting fast - with FBO / RBO extensions, glReadPixels() is speeding up (forget about PBO – Pixel Buffer Object)

  2. Minél inkább kevesebbszer történik az z-piramissal az összehasonlítás annál jobb: a biztosan látható elemek esetén nem szabad használni.
  3. Azt tapasztaltam, hogy felesleges felépíteni / használni a teljes a z-piramist kis méretű (64x64) z-buffer esetén. 
  4. Ha a jelenet nem tartalmaz elég megjelenítendő elemet / nem elég összetett, akkor kapcsoljuk ki az occlusion cullt, mert többet vesztünk CPU oldalon, mint amit a GPU oldalon nyerünk.
  5. Zsúfolt jelenet esetében akkor 10x - 15x teljesítmény növekedést is el lehet érni!

Mint látható maga az algoritmus semmiféle térfelosztó tulajdonsággal nem bír, hanem csak "mindössze" egy láthatósági vizsgálat. Ahhoz, hogy igazán hatékony legyen az algoritmus egy olyan térfelosztott jelenettel együtt kell használni, ahol igaz a hierarchiára, hogy ha szülő nem látszik, akkor a gyerekei sem. Ilyenkor a sokat emlegetett elemek a térfelosztási hierarchia csomópontjai és levelei.

 

Szólj hozzá!

Címkék: occlusion cull hierarchical z buffer visibility

OpenGL múzeum - GL_EXT_vertex_array_set és GL_ARB_vertex_array_object

2010.06.16. 17:24 :: syam

GL_EXT_vertex_array_set és GL_ARB_vertex_array_object

Igen érdekes párost alkotnak hiszen kettőjük között közel 10 év különbség van: az utóbbi mindössze 2 éve jelent meg míg az első elvileg 1997-ben, gyakorlatilag viszont vélhetően soha hiszen az egyéb csoportban foglal helyet a registry-ben.
Valószínűleg nem kiforrott extension volt megszületésekor (object helyett set-nek nevezték). Kérdés vajon miért vártak 10 évet egy "átnevezésre".

A használatuk és hasznuk gyakorlatilag ugyanaz. Egy új OpenGL object típust definiálnak, amely példányaihoz különböző vertex array-okat lehet kötni. Magának a vertex array objectnek a kötésekor a hozzá kötött vertex arrayok kötése történik meg. Vagyis egy bind függvény hívásával egyszerre több vertex arrayt bind-olhatunk.

Szólj hozzá!

Címkék: opengl muzeum

OpenGL múzeum - GL_EXT_static_vertex_array és GL_EXT_compiled_vertex_array

2010.06.16. 10:27 :: syam

GL_EXT_static_vertex_array és GL_EXT_compiled_vertex_array

Ez a két extension a szinte teljesen megegyező leírásukat tekintve nagyon nagy valószínűséggel ugyanaz annyi különbséggel, hogy az előbbit a registry az others csoportban jelöli meg vagyis gyaníthatóan nem került be sohasem driverbe (még sorszámot sem kapott) míg a másik még ma is megtalálható az extension listákban. Az egyik 1997 míg az utóbbi 1996 évjárattal szerepel a registry-ben.

Működésük:
A két találóan elnevezett függvény (lock és unlock) jól mutatja az extension elvét. Ha kiadjuk a lock parancsot akkor ezzel a függvénnyel megadott vertex tartományba eső, az éppen engedélyezett vertex array-okat nem módosíthatónak tekinti az OpenGL (a másik extension leírása mindössze egy bizonyos compile-t említ ezekre az adatokra). Értelemszerűen ezt az állapotot az unlock paranccsal lehet felfüggeszteni.
Hogy ez valójában milyen optimalizációt jelent nem igazán lehet tudni, mert még nem észleltem teljesítmény változást a használatakor.

 

Szólj hozzá!

Címkék: opengl muzeum

süti beállítások módosítása