Kirjoittaja: peki
Tuli on pehmennysfiltterin sovellusta käyttävä palettiefekti. Ideana on piirtää ensin piirtää pohjakuvio kirkkaalla värillä, sitten kuviota pehmennetään ja sitä siirretään ylöspäin. Sitä kylmennetään kylmennyskartasta otettavilla väriarvoilla. Tästä efektistä on olemassa erittäin mielenkiintoisia versioita. Suosittelen esimerkiksi kokeilemaan erilaisia valumissuuntia oppaan luettuasi.
Aivan ensimmäiseksi tarvitsemme kaksi ruudun kokoista taulukkoa, jotka sisältävät edellisen ja nykyisen ruudun dataa. Taulukot sisältävät jokaisen pikselin kuumuuden.
int buffer1[SCREENWIDTH][SCREENHEIGHT]; int buffer2[SCREENWIDTH][SCREENHEIGHT];
Jokaisen ruudun alussa on piirrettävä lieskojen aloitusdata. Piirtäkäämme nyt viiva ruudun alaosaan.
for (int i = 0; i < 20; i++) { buffer1[SCREENHEIGHT / 2 - 10 + i][SCREENHEIGHT - 10] = 255; buffer1[SCREENHEIGHT / 2 - 10 + i][SCREENHEIGHT - 11] = 255; }
Seuraavaksi puhutaan itse algoritmista. Tässä efektissä on käytävä jokainen pikseli yksitellen läpi. Sitä ei voi mitenkään kiertää.
// käydään koko ruutu läpi for (int x = 1; x < SCREENWIDTH-1; x++) { for (int y = 1; y < SCREENHEIGHT-1; y++) { ... } }
Kyseisen silmukan sisällä meidän on laskettava jokaista pikseliä ympäröivien pikselien keskiarvo ja sijoitettava se yhtä pikseliä ylemmäs. Tämän takia silmukka alkaa ykkösestä eikä nollasta. On aivan itsesi päätettävissä, otatko keskiarvon kaikista ympäröivistä pikseleistä vaiko vain neljästä. Efektin ulkonäköön se vaikuttaa vain hieman. Pikseli, jota ympäröivien pikselien keskiarvoa mitataan, voidaan myös sisällyttää halutessa keskiarvoon.
Tämä kuva selventää asiaa:
A = Vuorossa oleva pikseli.
B = Pikseli, johon keskiarvo sijoitetaan.
1, 2, 3, 4 = Pikselit, joista keskiarvo otetaan.
A:n arvoa ei kuitenkaan vielä tässä vaiheessa muuteta!
Koodina siis näin:
// ympäröivien pikselien keskiarvo int c1 = buffer1[x+1][y+1]; int c2 = buffer1[x-1][y-1]; int c3 = buffer1[x-1][y+1]; int c4 = buffer1[x+1][y-1]; uusivari = (c1 + c2 + c3 + c4) / 4; buffer2[x][y-1] = uusivari;
Mielessäsi saattaa olla nyt eräs kysymys. Jos suoritamme tämän monta kertaa ja piirrämme pohjakuvan aina uudestaan, ruutuhan muuttuu kokonaan valkoiseksi. Tämän takia puhumme nyt kylmennyskartasta.
Tuli ei ole mitään ilman kylmennyskarttaa. Kylmennyskartalla saat tulen väreilemään ja lieskat hulmuamaan. Kylmennyskartta on erittäin tummasävyinen kuva, jossa on vain tietyn värin sävyjä, tässä tapauksessa punaisen.
Jokaisen pikselin kohdalla kylmennyskartasta otetaan pikseli vastaavasta kohtaa ja vähennetään sen arvo pehmennetyn värin arvosta. Kylmennyskarttaa pyöritetään ylöspäin joka kerta, kun yksi ruutu on piirretty.
Koodina:
// väri kylmennyskartasta // kylmakohta on eräänlainen offsetti karttaan. se kertoo, mistä kohtaa otetaan mikäkin pikseli. // Jos y - kylmakohdasta tulisikin pienempi kuin nolla, eli mentäisiin kartan yläpuolelle, siirrymmekin kartan alareunaan ja jatkamme sieltä. Lopussa kasvatamme kylmakohdan arvoa sopivalla luvulla. Uint32 c; // Tämä on etumerkitön 32 bittinen kokonaisluku, jota käytämme bittishiftien ja andauksen helpottamiseksi. //Tärkeintä on kuitenkin vain saada talteen värin punainen osa ja voit siihen käyttää vapaasti omia keinojasi. if (y - kylmakohta >= 0) c = getpixel(kylma, x, y - kylmakohta); else c = getpixel(kylma, x, SCREENHEIGHT + y - kylmakohta); // otetaan talteen kylmennyskartan punaväri (8 ylintä bittiä; väri on 24 bittinen). Tämä väri voisi tietysti olla mikä tahansa. // Johtuen 256 värisestä paletista haluamme kuitenkin vain 8 bittisen väriosan. uusivari -= ((c >> 16) & 0xff); if (uusivari < 0) uusivari = 0; // piirretään pehmennetty ja kylmennetty pikseli ylöspäin, jotta saadaan liekit menemään ylöspäin buffer2[x][y-1] = uusivari;
Jos et jaksa tai halua tehdä kylmennyskarttaa, voit tietenkin vähentää väristä myös jonkun arvotun arvon. Efekti on kyllä tällöin erittäin paljon heikomman näköinen.
Paletin on syytä olla moniväriliuku. Esimerkiksi valkoisen, keltaisen ja oranssin kautta punaiseen, jonka kautta vielä mustaan. Palettien tekemiseen suosittelen T.M.:n tekemää generaattoria.
Paletit voi toki tehdä myös fysiikan lakien mukaan laskemalla heijastuvan valon aallonpituudet kuumuuden mukaan, mutta sitä en tässä oppaassa käsittele.
On tullut aika yhdistää tämä kaikki yhdeksi koodiksi. Muista kopioida Puskuri1 puskuri2:een lopuksi, sekä piirtää alkuperäinen kuvio aina uutta ruutua aloitettaessa.
Tässä se nyt on.
int buffer1[SCREENWIDTH][SCREENHEIGHT]; int buffer2[SCREENWIDTH][SCREENHEIGHT]; void Piirratuli() { for (int i = 0; i < 20; i++) { buffer1[SCREENHEIGHT / 2 - 10 + i][SCREENHEIGHT - 10] = 255; buffer1[SCREENHEIGHT / 2 - 10 + i][SCREENHEIGHT - 11] = 255; } // käydään koko ruutu läpi for (int x = 1; x < SCREENWIDTH-1; x++) { for (int y = 1; y < SCREENHEIGHT-1; y++) { // ympäröivien pikselien keskiarvo int c1 = buffer1[x+1][y+1]; int c2 = buffer1[x-1][y-1]; int c3 = buffer1[x-1][y+1]; int c4 = buffer1[x+1][y-1]; int uusivari = (c1 + c2 + c3 + c4) / 4; // väri kylmennyskartasta Uint32 c; // Tämä on etumerkitön 32 bittinen kokonaisluku, jota käytämme bittishiftien ja andauksen helpottamiseksi. //Tärkeintä on kuitenkin vain saada talteen värin punainen osa ja voit siihen käyttää vapaasti omia keinojasi. if (y - kylmakohta >= 0) c = getpixel(kylma, x, y - kylmakohta); else c = getpixel(kylma, x, SCREENHEIGHT + y - kylmakohta); // otetaan talteen kylmennyskartan punaväri (8 ylintä bittiä; väri on 24 bittinen). Tämä väri voisi tietysti olla mikä tahansa. // Johtuen 256 värisestä paletista haluamme kuitenkin vain 8 bittisen väriosan. uusivari -= ((c >> 16) & 0xff); if (uusivari < 0) uusivari = 0; // piirretään pehmennetty ja kylmennetty pikseli ylöspäin, jotta saadaan liekit menemään ylöspäin buffer2[x][y-1] = uusivari; } } // Piirretään kuva näytölle for (int x=1;x<SCREENWIDTH-1;x++) for (int y=1;y<SCREENHEIGHT-1;y++) { putpixel(surface, x,y, paletti[buffer2[x][y]]); //vaihdetaan puskurit keskenään. buffer[x][y] = buffer2[x][y]; } // kylmennyskarttaa nostetaan ylös kylmakohta += 3; if (kylmakohta >= SCREENHEIGHT) kylmakohta = 0; }
Valmiin toteutuksen löydät sivustoni koodausosiolta.
Kuten jo tuossa alussa ilmaisin, suosittelen kokeilemaan erilaisia variaatoita tästä efektistä. Tällä pehmennyksellä saa monessa paikassa ihmeitä - ja vähän enemmänkin - aikaan.
Pyytäisin taas linkittämään omia versioita tästä efektistä, jos sellaisen viitsit tehdä.
Hyvää koodailua!
Pekka Järvinen, 25.9.2004
joo ihan hassu
Itse suosittelen tätä: http://koti.mbnet.fi/winuus/paletti.php?act=do&data=000000-FF0000-FFFF00-FFFFFF&lev=255-255-255&format=vari[%NUM] = rgb(%R,%G,%B); &file=http://&ff=
Vaikuttaa aika hienolta. :)
nyt minäkin tajusin hieman "grafiikan" tekniikkaa.
ois niin ihana jos ois binaari tai vb6... yritin tehdä vb6:lla oman mut iha kämäne oli
eikä ees sisältäny tommosia...
Olen itse joskus koodannut pienen (186 tavua :) tuliohjelman seuraavanlaisella algoritmilla:
Jokaisen pikselin arvoksi tulee sen alapuolella olevaa ympäröivien pikselien keskiarvo. Näin tuli liikkuu ylöspäin. Jos halutaan, että tuli feidaantuu vähän nopeammin, vähennetään tästä arvosta vielä yksi.
Kylmennyskarttaa ei tarvita, kun screenbufferiin varataan pari ylimääräistä scanlineä, joita ei tietenkään piirretä ruudulle. Näille kahdelle riville piirretään joka iteraatiolla satunnaisiin paikkoihin muutamia hotspotteja (paletin maksimiarvolla), ja taas muutamia 0-arvoja, jotta tuli ei pääse missään vaiheessa "valloilleen" :)
Mutta juu, näitähän voi tehdä monella tavalla.
Mukaan pitäisi laittaa MSVCR70.DLL.
Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.