Fire effect

Fire effect - algoritmus

 

Původní grafické módy využívaly hlavně rozlišení 320x200pixelů a paletu 256barev.

Řádků bylo 200, přibližně stejně bylo i barev, optimální předpoklad pro zaplnění obrazovky ohněm :)

Na spodní řadu obrazovky se umístí několik bodů vysokého jasu a ty se postupně ztmavují, přičemž se bere do úvahy hodnota na předchozím řádku.

 

Paleta barev by se měla optimálně skládat z přechodu barev

černá - červená 0 až 130

a

červená - žlutá 131 až 254

Můžete zakombinovat i bílou. Záleží na spalovaném materiálu :)

 


// generování palety barev. Nejdříve odstíny červené, které přejdou v jasně žlutou
IList PALlist = new List();
for (byte i=0;i<255;i++)
{
    if (i<130)
        PALlist.Add(Color.FromRgb(i, 0, 0));
    else
        PALlist.Add(Color.FromRgb(i,(byte)(i-130), 0));

}

 

samotné zobrazení realizuji pomocí writeablebitmap takto


BitmapPalette myPalette;
myPalette = new BitmapPalette(PALlist);
wBmp = new WriteableBitmap(xres, yres, 96, 96, PixelFormats.Indexed8, myPalette);

 

 zde je potřeba říci, že Writeablebitmap s pixelformatem indexed8 je pomalejší než Bgra32. Já ve verzi pro desktop použil indexed8, ale ve verzi pro Silverlight jsem už paletu nenastavoval a použil jsem rovnou Argb32 (nic jiného Silverlight ani nenabízí)

 

dále jsem si založil 2 buffery. Jeden s integer hodnotou a druhý byte.

Ten s integer slouží pro samotné generování ohně. Hodnoty větší než 256 mi tak dovolí mít vyšší oheň, nedochází k tak rychému ztmavení. Pole byte potom slouží k samotnému zobrazení výsledku na obrazovku.

 


int[,] BuffArray1 = new int[yres + 1, xres];        // zde kreslíme samotný oheň
byte[,] BuffArray4 = new byte[yres + 1, xres];     
// pole typu integer nejde jednoduše poslat do bitmapy, proto musím bohužel konvertovat 

 

Na začátku každého obrazu je potřeba do spodní části obrazovky vegenerovat jasné body.

V mém případě jsem spodní dva řádky nejprve pokryl náhodnou hodnotou barvy 120 - 150, tedy světlé odstíny červené a dále jsem do spodní části umístil několik větších bodů 3x3pixely hodnoty 255, tedy jasně žlutou.

Proměnnou násobič jsem použil pro zvětšení rozsahu barevnosti a tedy i samotné výšky ohně. Pokud bych měl jen 255 řádků, oheň by byl velmi nízký. Místo hodnoty 255 je tak uložena hodnota 510 (podle násobiče = 1 bitový posun vlevo).

 


// umístím náhodné body jasně červené do spodních dvou řad
for (int i = 0; i < xres; i++)
{
    BuffArray1[yres - 1, i] = (byte)rnd.Next(120, 150) << nasobic;
    BuffArray1[yres - 2, i] = (byte)rnd.Next(120, 150) << nasobic;
}

// umístím několik větších bodů vysokého jasu žluté také do spodní řady
for (int x = 1; x < rnd.Next(9, 50); x++)
{
    int i;
    i = rnd.Next(1, xres -1);
    BuffArray1[yres - 1, i-1]    = 255 << nasobic;
    BuffArray1[yres - 1, i]      = 255 << nasobic;
    BuffArray1[yres - 1, i+1]    = 255 << nasobic;
    BuffArray1[yres - 2, i - 1]  = 255 << nasobic;
    BuffArray1[yres - 2, i]      = 255 << nasobic;
    BuffArray1[yres - 2, i + 1]  = 255 << nasobic;
    BuffArray1[yres - 3, i - 1]  = 255 << nasobic;
    BuffArray1[yres - 3, i]      = 255 << nasobic;
    BuffArray1[yres - 3, i + 1]  = 255 << nasobic;
}

 

 

 

Samotné generování pixelů ohně je znázorněno na tomto obrázku:

 

Pixel s křížkem je právě počítaný pixel a 4 zelené pixely jsou použity jako zdrojové pro výpočet hodnoty. Samotný výpočet je jen aritmetický průměr. 

Počítá se každý pixel řádku od spodního k hormímu. Hodnota -1 znamená cílené ztmavení o jeden stupeň.

  

 

#include 
for (int y = yres - 1; y > 0; y--)
    for (int x = 1; x < xres - 1; x++)
    {
        b = (byte)((((BuffArray1[y, x - 1]) + (BuffArray1[y, x + 1]) + 
                           (BuffArray1[y + 1, x]) + (BuffArray1[y , x])) >> 2) - 1);
        if (b < 2) b = 2;
        BuffArray1[y - 1, x] = b;
    }


 

vygenerovaná scéna se zkonvertuje na pole typu byte a pošle na obrazovku. Co se původně jevilo jako nutné zlo se nakonec ukázalo, jako dobrý nástroj k přizpůsobení vzhledu ohně. Schválně si zkuste smazat podmínku ii>254, uvidíte, co se stane a jak toho bylo využito k lepšímu efektu.


for (int y = 0; y < yres; y++)
    for (int x = 0; x < xres; x++)
    {
        if (radioButton3.IsChecked == true)
        {
            if (BuffArray1[y, x] > 254) BuffArray1[y, x] = BuffArray1[y, x] + 8;
            ii = BuffArray1[y, x];
            if (ii > 254) ii=254;
            BuffArray4[y, x] = (byte)(ii);
        }
 }

wBmp.WritePixels(new Int32Rect(0, 0, xres, yres-5), BuffArray4, xres, 0);

 

 Místo generování náhodných hodnot na spodní stranu obrazovky můžete generovat body ve tvaru nějakého objektu, případně i textu a mít tak hořící nápisy.

 

 





Kontakt M: 724 085 607 E: info@bura.cz

© Bura.cz