Az NVScene-re készített produkciónk az első Androidos demónk, ezért igyekeztem minimalista demók készíteni, hogy a platform részletes ismeretének hiánya ne akadályozza az alkotás elkészültét. Így esett a választás a metaball kétdimenziós változatára, a metakörre.
A metakörrel érdekes alakzatokat lehet kirajzolni. Ha közel kerülnek egymáshoz, egy részük kidudorodik, mintha vonzanák egymást. Ez a tulajdonságuk azért is hasznos, mert felbontás és képernyő arány függetlenek, tehát bármilyen eszközzel nézik meg a demót, az mindig korrektül fog megjelenni.
Egy másik hasznos tulajdonságuk, hogy pixel shaderben lehet implementálni a megjelenítésüket. Ez azért hasznos, mert nem kell poligonokat importálni, elég egy kis kódot írni és máris megjelennek. A metakörök jellemzőit uniform változókon keresztül akartam beadni. A uniform változók száma viszont rendszer függő. Egy NVidia Shield esetén valószínűleg magas a számuk, de én gondoltam a régi, leszázalékolt telefonokat használókra is (főleg, mert nekem is azok vannak), ezért egy kis tesztprogrammal megnéztem, mennyi változóval birkózik meg egy Sony Tipo. A mérések alapján 40 elfogadható sebességet produkál.
Történetet is akartam, amiben kihasználom a metakörök csápszerű nyúlványait. Eredetileg egy Magyar ugaron ihletésű jelenetre gondoltam, ahol a gazok egy ember után nyúlnak, visszahúzzák, stb. Ehez metakörökkel kirajzolt képekre volt szükségem.
Grassnak ezért készítettem egy Windowsos rajzoló programot. A kíváncsiak letölthetik innen. Grass azt mondta, hogy ezek a bogyók egyszerűen nem alkalmasak arra, hogy felismerhető grafikát készítsünk velük. Természetesen nem értettem egyet vele. Megpróbáltam én is rajzolni valami értelmeset a programmal, nekem sem ment. Arra gondoltam, ez bizonyára azért van, mert nem tudok rajzolni.
Ekkor született meg az ötlet, hogy a számítógépnek kéne rajzolnia. Én beadnék neki egy képet, a program pedig legenerálja a szükséges metakör adatokat. Mivel a metakörök között elég bonyolult interakciók lehetnek, ezért a megoldást egy genetikus algoritmusban láttam.
Készítettem is egy ilyen programot és néhány teszt futtatás után megállapítottam, hogy ez sem fogja a megfelelő eredményt produkálni. A demó végül teljesen procedurális lett, nem volt benne történet, de az ötödik helyet és a vele járó jutalmat (ami egy NVidia Shield tablet volt) elhoztuk.
A program felépítése egyszerű. Beolvas egy ASCII PBM fájlt, ami a legegyszerűbb bitkép formátum, ami létezik. Ebből is csak fekete-fehéret kezel. Elkészít 1000 darab ábrát, mindegyikben 40 metakörrel, amelyek paramétereit véletlen szerűen választja ki. Jaccard index segítségével összehasonlítja az összes képet az eredetivel. Kiválassza az 5 legjobbat, majd azokat véletlen szerűen elkezdi kombinálni, valamint bizonyos százalékban mutálja az utódok tulajdonságait. Képez újabb 1000 utódot és a művelet kezdődik elölről.
Kíváncsi voltam, hogyan befolyásolják az egyes paraméterek (mutáció gyakorisága, populáció mérete, stb.) az eredmény alakulását. Mivel a program rengeteg véletlen számmal dolgozik, igazából el sem tudtam képzelni, hogy lesz-e értelmes eredmény. A program ezért statisztikai céllal elmenti minden generációban a legjobb egyed által generált képet, valamint a populáció minden tagjának a Jaccard-indexét.
Az első és legfontosabb észrevételem, hogy a program viszonylag gyorsan elér 80% hasonlóságot, és onnan lelassul. Ennek az az oka, hogy nagyon precíz változásokra van szükség, hogy növekedjen a hasonlóság.
Másik észrevétel, hogy a magasabb mutációs ráta nem hozott gyorsabban eredményt, pedig ezt vártam volna. Talán a populáció méretét is növelhettem volna. De az egészben a legmegdöbbentőbb, hogy az algoritmus eredményeit úgy vizsgálom, mintha tényleg egy sok egyedes szuperorganizmus lenne. Akinek van kedve, játszhat a beállításokkal. A forráskód innen tölthető le.
Mivel elég lassan fut, megpróbálok egy Cuda gyorsított változatot is készíteni.
Végezetül nézzük meg, hogyan rajzolja ki a Denevérember logóját: