Leírás

3D grafikával kapcsolatos bejegyzések és cikkek. A Quadron Virtual Particle nevű game engine fejlesztése.

Stuff

Anything related to game development.

Contact: darthasylum at gmail dot com

Nemlineáris cikkek

Mi ezeknek a célja?

Leginkább az, hogy magyarul is elérhető legyen programozási anyag, olvasmányos formában.

A cikkek kódja GitHub-ról is elérhető. (*)-al jelölöm azt a cikket ami nemrégiben frissült.

A színek a nehézséget próbálják jelezni, de az, hogy egy cikk piros nem azt jelenti, hogy csak a profiknak szól!

 

 

 

 

 

 

 

 

Hörcsög

The Asylum

3D grafikával kapcsolatos bejegyzések és cikkek. A Quadron Virtual Particle nevű game engine fejlesztése.

Friss topikok

Címkék

HTML

3D objektum mozgatás egérrel

2013.06.02. 22:54 | darthasylum | Szólj hozzá!

Kicsit kutattam, mert nem voltam elégedett a BIMx-ben implementált megoldással (nem követi az ujjad). Végül háromféle megoldással álltam elő: cikk.

A leírt módszerek mindegyike alkalmazható tetszőleges objektumra, tetszőleges mozgási irányra (akár egyszerre többre is), némi meggondolással.

Fókusz menedzsment

2013.05.21. 22:45 | darthasylum | Szólj hozzá!

A feladat a következő: adott egy modelviewer, amiben lehet forgatni a kamerát az egér lenyomva tartásával. A modelviewernek viszont van GUI-ja is (az engine-el rajzolva), ami szintén az egérrel működik. Hogyan lehet biztosítani a kölcsönös kizárást (az egeret csak egy valami birtokolhassa egy adott időben)? Kérdezek jobbat: hogyan lehet adott esetben megkerülni a kölcsönös kizárást?

Az elvárások a vázolt esetben az alábbiak:

  • a GUI elsőbbséget élvez
  • a kamera klikkelésre kap fókuszt, a GUI viszont egérmozgatásra (hover)
  • ha a kamera birtokolja a fókuszt, akkor a GUI nem reagál semmire
  • ha a GUI birtokolja a fókuszt, akkor a kamera nem reagál

Az eddigi megoldás ilyen hackelés szerű volt: a kamera értesítette a GUI-t, hogy megszerezte a fókuszt, a GUI ilyenkor letiltotta magát. A GUI értesítette a főprogramot, hogy megkapta a fókuszt, a főprogram letiltotta a kamerát (meg mást is csinált, de feleslegesen).

Egy másik feladatban kicsit más a helyzet:

  • a GUI és a kamera viszonya ugyanaz
  • de van egy harmadik elem, egy nagyító
  • a nagyító kizárja a GUI-t
  • a GUI kizárja a nagyítót
  • a nagyító a kamerával együtt tud működni

Több feltételt is teljesíteni kell tehát, másrészt könnyen jöhet olyan eset, hogy sok objektum birtokolhatja a fókuszt és akkor a 0. megoldás követhetetlen.


1. megoldás: event ignore

A legtöbb ilyen checkbox1_clicked() esemény szignálokkal van megoldva. A probléma az, hogy a szignálok tüzelését nem lehet megszakítani. Ha meglehetne, azzal egy objektum kisajátíthatja a fókuszt. Ez egy (nagyon) rossz megoldás, egyrészt mert az összes helyen át kell írni a slotokat, hogy a szignált ignorálni lehessen (akár visszatérő értékkel, vagy 0. paraméterként átadva), másrészt ez egy óriási korlátozás az engine használója felé (bár megkerülhető).


2. megoldás: fókusz objektum

Egy singleton, amit egy lock-hoz hasonlóan meg lehet fogni. Alapvetően jó ötlet, de a fókusz megosztása nehézkes. Miben tároljam? Multimap? Dictionary? Hashtable? Akármelyiket is választom "lassú" lesz. Nyilván kell tartani azt is, hogy épp kik birtokolják a fókuszt (ez megint overhead).


3. megoldás: osztott nyomkövetés

Végülis ezt csináltam meg mert elég egyszerű megcsinálni, és rugalmas. Csináltam egy Focusable nevű osztályt, aminek a lényege annyi, hogy a nyilvánvaló Acquire() és Unacquire() metóduson kivül van neki egy focuschanged<bool> szignálja és egy onfocuschanged(bool) slotja. A member változók pedig: hasfocus, canfocus, refcount.

Minden olyan osztály ami tud fókuszt szerezni, az ebből kell származzon. A kölcsönös kizárás biztosítása a programozóra van bízva, mégpedig úgy, hogy az egyik objektum szignálját ráköti egy másik slotjára (amennyiben az egyik kizárja a másikat).

Na de hogyan is működik és miért működik?

Focusable::Focusable()
{
    hasfocus = false;
    canfocus = true;
    refcount = 0;
}

void Focusable::AcquireFocus()
{
    if( !hasfocus )
        focuschanged(hasfocus = true);
}

void Focusable::UnacquireFocus()
{
    if( hasfocus )
        focuschanged(hasfocus = false);
}

void Focusable::onfocuschanged(bool otherhasfocus)
{
    if( otherhasfocus )
        ++refcount;
    else if( refcount > 0 )
        --refcount;

    canfocus = (refcount == 0);
}

Bár az Acquire()-be be lehetne rakni a canfocus-t is feltételnek, nem raktam be. Ezek után a fenti nagyítós példára a következőket kell csinálni:

form->focuschanged.connect(&camera, ...);
form->focuschanged.connect(magnifier, ...);
magnifier->focuschanged.connect(form, ...);
camera.focuschanged.connect(form, ...);

A ... mindenhol &Focusable::onfocuschanged (nem fér ki)...

Annyi megkötés van (de ez elég nyilvánvaló), hogy a mousedown eseményre először a GUI-t kell rákötni (hogy ha tudja, akkor ő kaphassa meg először a fókuszt).

viewer1.jpg
Ez nem a nagyítós példa

Ez a megoldás tűnik a legjobbnak, és semmiben sem korlátoz (ha nem akarod használni, nem használod). Memóriaügyileg elhanyagolható, teljesítményben pedig a szignál implementációjától függ (ami viszont már egy létező objektum, így plusz teljesítményromlás nincs).

OpenGL core profile

2013.05.13. 19:50 | darthasylum | Szólj hozzá!

A feladat az volt, hogy járjak utána a core profile-ra való áttérés lehetőségeinek, és írjak egy cikket. Mivel hasznosnak gondolom az eredményeket, ezért ide is kirakom. Itt olvasható.

Elég szomorú dolog, hogy Mac-en brutálisan rossz a teljesítmény, ezt jelentettem az Apple-nek. Remélem, hogy csak én rontok el valamit (bár amilyen driver bugok vannak, van egy sanda gyanúm, hogy nem...).

Fixed time step refactoring

2013.04.19. 21:58 | darthasylum | 5 komment

Az mindenki számára evidens, hogy a játéklogikát függetleníteni kell a rendereléstől, és ehhez nem elég, hogy 1 / fps-el felszorzol, mert instabil (átugrálsz a falon). Az engine a kezdetektől fogva 10 ups-en updatelte az állapotokat, rendereléskor pedig lineárisan interpolált (ahogy azt kell).

A baj csak annyi, hogy 10 ups-re volt belőve, azaz ha gyorsabban akartam updatelni (pl. az új fizikai engine miatt), akkor minden annyiszor gyorsabb lett. A feladat, hogy legalább az engine által nyújtott animátor független legyen az update rátától is.

Ez egy jó alkalom volt arra, hogy a timert is kicsit átbuheráljam. Double-el számolni jó dolog, de a nagy pontosságú órák minden platformon 64 bites integert adnak vissza; márpedig azzal számolva sokkal pontosabb lehet a logika ütemezése (és remélem, hogy a némely gépeken előforduló periodikus megakadás is megszűnik ezáltal).

Amit meg kell jegyezni, hogy Mac-en az unsigned long 64 bites (ha arra fordítasz), míg windowson nem. Mac-en egyébként az engine most már csak 64 bitre fordul, ezt egy gyenge pillanatomban csináltam meg, mivel az automatic reference counting csak úgy működik (de a leakes problémáimat nem oldotta meg...).

A refactoring első része tehát az ütemezőt érintette, ahol is a double-öket uint64-re cseréltem le. Ez volt a könnyebbik rész... a második rész viszont egy kapitális szopás volt.

Az animátor ugyanis eddig úgy működött, hogy a [0, 1] intervallumot felosztotta N darab részre; azaz létrehozott egy N elemű tömböt és kiszámolta bele az adott polinom értékeit (ezzel diszkretizálva). Az első verzió az volt, hogy ez maradhat, csak akkor nagyobb N-et kell megadni. Alapvetően jó is, de egyrészt fölöslegesen több memória, másrészt az animációk sebessége szemmel láthatóan eltért ha nagyobb volt a ráta.

Ezt tehát full újraírtam úgy, hogy most már időtartamot vár és nem tárol tömböt. Akkor viszont tudnia kell az update rátát. Ami baromira szar, mert eddig mindig olyan helyen inicializáltam, ahol még nem is volt beállítva. Szóval végig kellett verni az egész enginen.

Amit viszont nem csináltam meg, az a konkrétan 10 ups-től függő dolgok. Lusta módon az 1.7-es demóban az időt nem a timerrel mérem, hanem számolom az update tick-eket. Tehát 60 ups-el 6-szor olyan gyorsan telik az idő. De ez alapvetően nem baj, gondoljunk a Prince of Persia-ban az időlassításra: a játék belassul, de az interfész nem! Ezzel kvázi ingyen megoldható (lenne...sajnos a fizika alapból független...).

Deferred rendering

2013.04.02. 10:02 | darthasylum | Szólj hozzá!

Körül akartam járni a témát, hogy mégis képben legyek és ez alapján tervezzem meg az enginebe való integrálást. A teszt progik olyan jól sikerültek, hogy ez lett a köv. tutoriál. Bár igazából ez már nem tekinthető tutornak mert nem olyan szájbarágós, inkább csak körítés a kód mellé.

A tutoriál itt olvasható. A kódhoz javasolnám, hogy mostantól githubról szedjétek, egyrészt mert mindig up-to-date, másrészt én is az onnan letöltött zip-et rakom be dropboxba.

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