Základní myšlenka
Na začátku je třeba vygenerovat paletu barev, kterou použijeme pro náš oheň. Vybereme 300 odstínů, které budou plynule přecházet od bílé přes oranžovou, červenou až do černé.Poté vyplníme spodní řádek obrázku náhodně černou a bílou barvou a odshora dolů začneme ostatní pixely počítat dle pravidel uvedených níže. Budeme používat následující pojmenování pixelů
Implementace
Na začátku deklarujeme proměnné a definujeme konstanty. Také vytvoříme okno.#include <cmath> #include "quickcg.h" using namespace QuickCG; const int POCET_BAREV = 300; const int OBRAZOVKA_SIRKA = 400; const int OBRAZOVKA_VYSKA = 400; const int CERNA_R = 0; const int CERNA_G = 0; const int CENRA_B = 0; const int CERVENA_R = 255; const int CERVENA_G = 0; const int CERVENA_B = 0; const int ORANZOVA_R = 255; const int ORANZOVA_G = 170; const int ORANZOVA_B = 0; const int BILA_R = 255; const int BILA_G = 255; const int BILA_B = 255; const int PALIVO = 25; int main(int argc, char *argv[]) { ColorRGB barva; Uint32 ohen[OBRAZOVKA_SIRKA][OBRAZOVKA_VYSKA]; Uint32 buffer[OBRAZOVKA_SIRKA][OBRAZOVKA_VYSKA]; Uint32 paleta[POCET_BAREV]; float inkrement1; float inkrement2; int novaBarva; int nahodneCislo; //inicializuj obrazovku screen(OBRAZOVKA_SIRKA, OBRAZOVKA_VYSKA, 0, "ohen"); [/sourcecode] Teď si vynulujeme pole s budoucími hodnotami ohně. [sourcecode language='c++'] //nastav výchozí hodnoty pro oheň for(int x = 0; x < w; x++) { for(int y = 0; y < h; y++) { ohen[x][y] = 0; } }Čas na definování palety. První třetina bude přechod od černé do červené, druhá od červené do oranžové a třetí od oranžové do bílé.
//barvy 0 - 99 barva.g = CERVENA_G; barva.b = CERVENA_B; inkrement1 = (float)CERVENA_R / (float)99; for(int i = 0; i < 100; i++) { barva.r = ceil(inkrement1 * i); paleta[i] = RGBtoINT(barva); } //barvy 100 - 199 barva.r = ORANZOVA_R; barva.b = ORANZOVA_B; inkrement1 = (float)ORANZOVA_G / (float)99; for(int i = 100; i < 200; i++) { barva.g = ceil(inkrement1 * (i - 99)); paleta[i] = RGBtoINT(barva); } //barvy 200 - 299 barva.r = BILA_R; inkrement1 = (float)(BILA_G - ORANZOVA_G) / (float)99; inkrement2 = (float)(BILA_B) / (float)99; for(int i = 200; i < 300 - 1; i++) { barva.g = ORANZOVA_G + ceil(inkrement1 * (i - 199)); barva.b = ceil(inkrement2 * (i - 199)); paleta[i] = RGBtoINT(barva); }Vše je připraveno pro spuštění animace. Pokračujme tedy smyčkou a spouštěcím mechanismem. Na začátku musíme vygenerovat první řádek dle jednoduchého předpisu. Pokud náhodné číslo v intervalu <0> bude 0, pak na dané pozici dáme černý pixel. Pokud 1 tak bílý a pokud cokoliv jiného necháme ho beze změny.
while(!done()) { //nastav palivo for(int x = 0; x < w; x++) { nahodneCislo = rand() % PALIVO; if (nahodneCislo == 1) { ohen[x][h - 1] = 299; } else if (nahodneCislo == 0) { ohen[x][h - 1] = 0; } }Následující část představuje samotný výpočet. Vložte kód jedné z následujících technik.
...Zbývá už jen definování bufferu a jeho vykreslení na obrazovku.
//nastav buffer pro vykreslení for(int x = 0; x < w; x++) { for(int y = 0; y < h - 1; y++) { buffer[x][y] = paleta[ohen[x][y]]; } } //vykresli buffer drawBuffer(buffer[0]); redraw(); } return 0; }
Technika první
Pro každý pixel vezmeme tři, které leží bezprostředně pod ním. Z těchto tří uděláme aritmetický průměr a výslednou hodnotu uložíme do počítaného pixelu. \[ I_n=(I_a + I_b + I_c)/3 \]Následuje kód této techniky.
//vypočítej hodnoty pixelů na obrazovce for(int y = 0; y < h - 1; y++) { for(int x = 1; x < w - 1; x++) { novaBarva = (ohen[x-1][y+1] + ohen[x][y+1] + ohen[x+1][y+1]) / 3; if (novaBarva > 0) { novaBarva = novaBarva - 1; } ohen[x][y] = novaBarva; } }
Technika druhá
Pro každý pixel vezmeme hodnotu tří, které leží pod ním, stejně jako v předchozím případě a přidáme i původní hodnotu počítaného. Vydělíme čtyřmi a výsledek použijeme. \[ I_n=(I_a + I_b + I_c + I_n)/4 \]//vypočítej hodnoty pixelů na obrazovce for(int y = 0; y < h - 1; y++) { for(int x = 1; x < w - 1; x++) { novaBarva = (ohen[x-1][y+1] + ohen[x][y+1] + ohen[x+1][y+1] + ohen[x][y]) / 4; if (novaBarva > 0) { novaBarva = novaBarva - 1; } ohen[x][y] = novaBarva; } }
Dodatek
Všimněte si, že je nutné odečíst z indexu barvy 1, pokud je to možné. Tímto simulujeme postupné slábnutí plamenů, protože čím menší hodnotu barva má, tím jde více do černa. Můžete zkusit co se stane, když jedničku odečítat nebudete.Literatura a odkazy
Videa a článek co mě inspirovalyhttp://www.youtube.com/watch?v=NSI4KKjYS_w - porovnání obou přístupů
http://www.youtube.com/watch?v=_SzpMBOp1mE - jednoduchá implementace spolu s mluveným komentářem, appletem a zdrojovými kódy
http://www.youtube.com/watch?v=iezD8B1ym3w - vylepšení implementace z předchozího videa
http://www.academictutorials.com/graphics/graphics-fire-effect.asp - další z možností jak naprogramovat oheň
Zdrojový kód
Stahujte zde.
Žádné komentáře:
Okomentovat