sunnuntai 18. toukokuuta 2008

Flash 10 beta

Flash 10:nen ei vielä ole virallisesti julkaistu, mutta nyt jo hätäisemmät pääsevät sitä kokeilemaan. Tätä varten tarvitaan Flex3 Nightly Build Thu May 15, 2008 tai uudempi linkki. Muista myös ennen asennusta poistaa vanha flash koneestasi linkki. Asenna vanhan poistamisen jälkeen uusi Flash 10 beta player linkki. Pura sdk paketti haluamaasi hakemistoon ja varmista, että sieltä löytyy seuraavaa filu FLEX_SDK/frameworks/libs/player/10/playerglobal.swc.

Sitten vaikeampi osuus :).

Sinun pitää käsin muuttaa flex-config.xml tiedostoa. Se löytyy [flex_root]\frameworks\flex-config.xml. Tee tiedostosta varmuuskopio ja avaa alkuperäinen xml tiedosto johonkin tekstieditoriin.
Muuta tiedostoa seuraavasti.

Muuta target-player tagi arvoon 10.0.0. Muuta viittaukset playeriin 9 arvoon {targetPlayerMajorVersion}. Eli libs/player/9/playerglobal.swc rivi libs/player/{targetPlayerMajorVersion}/playerglobal.swc. Näitä kohtia on tiedostossa kaksi external-library-path ja library-path.

Nyt Flex on valmis kääntämään Flash 10 sälää. Jos haluat käyttää Flash Developia tarvitset uuden FD buildin FlashDevelop 3 SVN build from rev. 2297. Aseta se käyttämään uutta Flexiä ja lisää projektin External Libraries listaan [flex_root]\frameworks\libs\player\10\playerglobal.swc tiedosto. Tarvitset enää Flash 10 playerin IE:lle ja voit tehdä Flash 10 ohjelmia Flash Developilla.

Ohje englanniksi Flash Developin foorumilla.

maanantai 12. toukokuuta 2008

PaperVision 3D

Koska rasterointi pikseli pikseliltä on Flashilla erittäin hidasta pitää Flashin kanssa kikkailla, jotta pystytään renderoimaan 3d kamaa ruudulle. Tähän tarkoitukseen on olemassa useita 3d-moottoreita, jotka suoriutuvat tehtävästä jotakuinkin. Yksi näistä on suosittu PV3D, joka on ns. "skew rendaaja". Useimmat Flash 3d-enginet ovat skew rendaajia. Tämä on matemaattisesti oikeaa 3d:tä, mutta se on silti "huijausta". Mitään ei oikeasti rasteroida, joten emme tiedä pikselien 3d koordinaatteja paitsi verteksien kohdalla. Tästä johtuen emme voi mm. perspektiivikorjata tekstuureita. Syvyysdatan puute aiheuttaa myös paljon muitakin rajoituksia joita tosin joitain voidaan kiertää. Skew nimitys tulee tavasta jolla tekstuurit rendataan. Flash ei tue perspektiivitekstuureja, mutta spritejä voidaan skewata. Eli rotaatoimme ja skewaamme spriten sopivaan asentoon ja leikkaamme siitä polyn tarvitsevan osan ja piirrämme tämän polyn kohdalle. Näin saadaan aikaan tektuurit, mutta ilman perspektiivikorjausta, joka näkyy isoissa polyissa teksturen vääristymisenä. Jotkut enginet tosin dynaamisesti tesselloi polyja jolloin vääristyminen vähenee, mutta ei kuitenkaan kokonaan katoa. Oikea tapa tehdä 3d-moottori olisi rasterointi, josta olemmekin tässä blogissa puhuneet, mutta flashin tehot eivät siihen vielä riitä. Tässä kuitenkin tulevaisuuden varalle open source 3d rasteroija http://drawlogic.com/2008/04/11/as3-swfz-source-code-goes-open-source/.

Tällä kertaa kuitenkin on tarkoitus kokeilla PaperVisionia. Teemme sillä upean pyörivän laatikon :). Olen varma, että tulette hämmästymään lopputuloksen upeutta, mutta tarkoitus on kokeilla miten PV3D saadaan käyttökuntoon ei pörhistellä graafisilla hienouksilla.

http://www.verajankorva.com/blog/HelloCube.swf

Kuten huomaatte tekstuurit vääristyvät laatikon pyöriessä. Tämä johtuu juuri mainituista syistä ja laatikkoa ei dynaamisesti tesselloida pienempiin polyihin niin vääristyminen näkyy hyvin selvästi.

Koodi tähän on erittäin simppeliä ja suurempi haaste on saada PV3D sorsat donattua :).

Lähdekoodi http://www.verajankorva.com/blog/HelloCube.as

keskiviikko 7. toukokuuta 2008

Flashin suorituskyky

AS3 on sanottu olevan nopemapi kuin AS2. Se on totta, mutta AS3 ei silti tee Flashista nopeaa. Se on edelleen hidas ja jää pahasti jalkoihin vaikka Javalle. Tästä huolimatta Flash tuntuu olevan suositumpi (jumala yksin tietää miksi). No kun kerran Flashia halutaan niin koodataan sitten sitä. Ensin on kuitenkin syytä tietää missä pullonkaulat ovat.

Kokeilin ensin perus matikkakamat. Laskutoimitukset tehty 10 000 000 kertaa ja katsottu miten kauan meni. Tuloksia.

Kertolasku: 858ms
Jakolasku: 809ms
Potenssilasku: 931ms
Bittien siirto: 932ms
Miinuslasku: 821ms
Pluslasku: 817ms
Pluslasku integer: 815ms

Tulokset ovat varsin hämmentäviä ja varsinkin jakolaskun nopeus. Tämä ei vertaa mittaa toimitusten nopeutta esim. verrattuna Javaan tai C++:aan, mutta tämä kertoo mikä on hidasta ja nopeaa Flashin sisällä. Yleisesti jakolasku on hidas, mutta Flashissa se tuntuu olevan nopein. Samoin myös bittien siirto ja pontessilasku on liki samalla viivalla mikä on myös melko erikoista. Flash tekee selvästi jotain hyvin eri tavalla kuin useimmat ohjelmointikielet, mutta tämän testin valossa plus, miinus, kerto ja jakolasku ovat kaikki yhtä kalliita flashille. Bittien siirtely ei myöskään tuo lisänopeutta potenssilaskuun nähden. Erityisen harmillista koska nyt koodin optimointi on taas vähän vaikeampaa. Oikeastaan tämän testin valossa pitäisi suosia jakolaskua, joka kuulostaa hyvin väärältä, mutta siltä se vaikuttaisi :).

Sanotaan selvyyden ja pahan olon vuoksi, että kertolasku testi kestää C#:lla 16ms ja Flashilla siis 858ms. Eli C# on tässä noin 53 kertaa nopeampi. Voisi tuon perusteella sanoa, että esim. peli joka pyörii 20fps flashilla pyörisi noin 1060fps C#:lla. Ei ole yhtään kivaa, että Flash on niin suosittu :(.

Nopeuksia ehtolauseiden käytöstä. Tässä sama juttu kuin yllä eli operaatiot on tehty 10 000 000 kertaa ja mitattu niiden viemä aika.

1 kierron mittainen for lause: 905ms
If lause: 822ms
Switch/Case lause: 1271ms

Dynaaminen muistin varaus. Mitattu samalla tavalla kuin aikaisemminkin.

2 muuttujan luominen: 1199ms
2 muuttujan arvon vaihtaminen: 1193ms
Luokan luominen, jossa 2 muuttujaa: 9586ms

Tässä kohtaa on erityisen tärkeää huomata, että luokan luonti on todella runsaasti hitaampaa. Eli jos olet ajatellut tehdä vaikka XY luokan, jota käytät joka pikselissä niin se on todella huono idea :). Kannattaa enemmin tehdä kaksi muuttujaa X ja Y. Eli vältä pieniä luokkia aina kun se on mahdollista. Ei kuitenkaan kannata mennä liiallisuuksiin ja tehdä koodista epäselvää vain siksi, että yrittää välttää luokkia. Muuttujan luomisella tai muuttujan arvon asettamisella ei tunnu olevan juuri eroja.

tiistai 6. toukokuuta 2008

Kolmion rasterointi



Kuvan mukaisen kolmion täyttäminen yhdellä värillä ei ole niin helppoa miltä se kuulostaa. Toki Flash tarjoaa tähän valmiin funktion, mutta se funktio ei kelpaa meille enää siinä vaiheessa kun haluamme täyttää polygonin tekstuurilla perspektiivikorjattuna. Tästä syystä meidän on kirjoitettava oma poly filleri, jota voimme kehittää eteenpäin.
Tähän on monia tapoja, mutta tässä esittelen tavallisemman tavan, jossa polygoni täytetään vetämällä polygonin reunasta reunaan vaakaviivoja (scanline). En oikeastaan tiedä millä nimellä tätä algoritmia kutsutaan, mutta sanon sitä nyt vaikka scanline rasteriksi.
Eli kolmio on muoto jossa on kolme sivua (edge) ja kolme kärkipistettä (vertex).



Homma toimii siten, että interpoloimme A->B välin jolloin saamme AB reunan ja interpoloimme A->C välin jolloin saamme AC reunan ja interpoloimme B->C ja saadaan BC reuna. Sitten vedellään vaakaviivoja AB ja AC reunojen välille ja saadaan täytetty yläosa.



Sama BC ja AC välille ja saadaan myös fillattu alaosa. Näin koko kolmio on täytetty.



Tämän toiminnallisuuden kirjoittaminen koodilla ei ole aivan triviaalia, mutta se ennemminkin hiukan työlästä ja ikävää kuin vaikeaa.
Kolmio siis rasteroidaan kahdessa osassa. Tämä siksi että haluamme kolmion yhden sivun olevan suora, joka helpottaa vaakaviivojen piirtoa ja ennen kaikkea nopeuttaa niiden piirtoa. Vaakaviivahan on hyvin helppo piirtää. Meidän pitää vain kasvattaa X arvoa yhdellä kunnes ollaan loppupisteessä. Tämä on siis yksinkertainen plus lasku.
Eli aloitetaan kolmion halkaisusta. Tässä ei oikeastaan ole mitään hankalaa. Meidän pitää vain varmistaa, että verteksit ovat y suunnassa laskevassa järjestyksessä eli A on ylin piste ja C alin piste. Itse halkaisu käy ikään kuin itsestään.


var t:Point = null;
if (A.y > B.y)
{
t = A;
A = B;
B = t;
}

if (B.y > C.y)
{
t = B;
B = C;
C = t;
}

if (A.y > C.y)
{
t = A;
A = C;
C = t;
}


Kun tiedämme, että pisteet ovat oikeassa järjestyksessä voimme laskea polyn yläosan.


if (t.A.y != t.B.y)
{
var aex:Number = t.A.x;
var aed:Point = new Point(t.B.x - t.A.x, t.B.y - t.A.y);
var aes:Number = aed.x / aed.y;

for (var i:int = t.A.y; i < t.B.y; i++)
{
aex += aes;
cex += ces;

var x1:int = aex;
var x2:int = cex;
drawScanline(new Point(x1, i), new Point(x2, i), _bmp);
}
}


Loogisesti jatkamme tästä piirtämällä myös alaosan.


if (t.B.y != t.C.y)
{
var bex:Number = t.B.x;
var bed:Point = new Point(t.C.x - t.B.x, t.C.y - t.B.y);
var bes:Number = bed.x / bed.y;

for (i = t.B.y; i < t.C.y; i++)
{
bex += bes;
cex += ces;

x1 = bex;
x2 = cex;
drawScanline(new Point(x1, i), new Point(x2, i), _bmp);
}
}


Ja tässä koko koodi, joka näyttää kaikki tarpeelliset yksityiskohdat.

Lataa lähdekoodi