Metapalloja muistuttava efekti, joka luodaan phong kartoituksella. Todennäköisesti vanha efekti, mutta en tähän ainakaan aiemmin ole törmännyt. Huomattavasti metapalloja kauniimpi. Vaatii tosin myös enemmän laskentatehoa. Olen koodiin kommentoinut efektin toiminnan tarkemmin.
Reaaliaikaiseen suoritukseen pitäisi riittää +2Ghz prosessori. Jos ei, vähennä pallojen määrää.
Koodi ja exe on löydettävissä kotisivuiltani: http://koti.mbnet.fi/peku1/koodaus.htm
Jos haluat vaihtaa palettia, muista muuttaa min -makrolle annettavaa b -parametria vastaamaan taulukon alkioiden määrää - 1!
Edit: Muutin neliöjuuren käyttämään SSE:tä (kommentoi pois, jos tietokoneesi ei tue sitä). Exeä ei ole päivitetty.
#include "SDL.h" #include <math.h> enum { SCREENWIDTH = 640, SCREENHEIGHT = 480, SCREENBPP = 32, SCREENFLAGS = SDL_HWSURFACE | SDL_DOUBLEBUF }; // Pallo struct Ball { int x,y; }; // Varmistusmakro #define min(a, b)((a) < (b)) ? (a) : (b) //Pallot Ball phongballs[5]; // Paletti, joka on tehty T.M.:n generaattorilla. // Vaihtoehtoisen löydät lopusta. Muista muuttaa min -makron parametria.. Uint32 pal[] = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 131839, 263423, 395007, 526591, 658175, 789759, 921343, 1052927, 1184511, 1316095, 1447679, 1579263, 1710847, 1842431, 1974015, 2105599, 2237183, 2368767, 2500351, 2631935, 2763519, 2895103, 3026687, 3158271, 3289855, 3421439, 3553023, 3684607, 3816191, 3947775, 4079359, 4210943, 4342527, 4474111, 4605695, 4737279, 4868863, 5000447, 5132031, 5263615, 5395199, 5526783, 5658367, 5789951, 5921535, 6053119, 6184703, 6316287, 6447871, 6579455, 6711039, 6842623, 6974207, 7105791, 7237375, 7368959, 7500543, 7632127, 7763711, 7895295, 8026879, 8158463, 8290047, 8421631, 8487423, 8619007, 8750591, 8882175, 9013759, 9145343, 9276927, 9408511, 9540095, 9671679, 9803263, 9934847, 10066431, 10198015, 10329599, 10461183, 10592767, 10724351, 10855935, 10987519, 11119103, 11250687, 11382271, 11513855, 11645439, 11777023, 11908607, 12040191, 12171775, 12303359, 12434943, 12566527, 12698111, 12829695, 12961279, 13092863, 13224447, 13356031, 13487615, 13619199, 13750783, 13882367, 14013951, 14145535, 14277119, 14408703, 14540287, 14671871, 14803455, 14935039, 15066623, 15198207, 15329791, 15461375, 15592959, 15724543, 15856127, 15987711, 16119295, 16250879, 16382463, 16514047, 16645631, 16777215}; void DrawScene(SDL_Surface* surface, SDL_Event* event) { // Lukitse pinta, jotta voimme käsitellä pikseleitä suoraan if ( SDL_MUSTLOCK(surface) ) { if ( SDL_LockSurface(surface) < 0 ) { fprintf(stderr, "Can't lock the screen: %s\n", SDL_GetError()); return; } } // pointteri pinnan pikseleihin Uint8 *p = (Uint8 *)surface->pixels; float Lx, Ly, Lz, /*length*/ z, clrf; for(int y = 0; y < SCREENHEIGHT; y++) { for(int x = 0; x < SCREENWIDTH; x++) { clrf = 0; for (int n = 0; n < 5; n++) { // valon suuntavektori (vektori valon ja pikselin välille) Lx = phongballs[n].x-x; Ly = phongballs[n].y-y; Lz = 30; // valovektorin pituus z = Lx*Lx + Ly*Ly + Lz*Lz; __asm { movss xmm0, z rsqrtss xmm0, xmm0 rcpss xmm0, xmm0 movss z, xmm0 } //length = sqrtf(Lx*Lx + Ly*Ly + Lz*Lz); // Koska maaston korkeus sama, emme tarvitse muuta kuin z arvoa. // Normalisoidaan se. Lz /= z /*length*/; // Lisätään kokonaisväriin phongkartoitus. // Pistekertomista ei suoriteta, koska maasto on tasaista ja suunnattu kameraa kohti // Silloin x ja y arvoja ei tarvita. // Maaston normaalivektorin z on 1, joten silläkään kertominen ei hyödytä. // Pistekertominen tarkottaisi valon tulokulman ja pinnan normaalin välistä kulmaa, // sen avulla voidaan laskea valon kirkkaus. // (dot * heijastus * dot^2*valoisuus + ambientti) clrf += Lz*127+Lz*Lz*128; if (n == 4) *(Uint32 *)(p + y * surface->pitch + x * 4) = pal[(int)(min(clrf,255))]; } } } // poistetaan lukitus if ( SDL_MUSTLOCK(surface) ) { SDL_UnlockSurface(surface); } //päivitä pinta SDL_Flip(surface); } int main(int argc, char* argv[]) { // Alusta sydeemit SDL_Init(SDL_INIT_VIDEO); atexit(SDL_Quit); // Luodaan ikkuna SDL_Surface* pSurface = SDL_SetVideoMode ( SCREENWIDTH, SCREENHEIGHT, SCREENBPP, SCREENFLAGS ); // Alustetaan pallot phongballs[0].x = 100; phongballs[0].y = 100; phongballs[1].x = 200; phongballs[1].y = 200; phongballs[2].x = 300; phongballs[2].y = 400; phongballs[3].x = 100; phongballs[3].y = 300; phongballs[4].x = 400; phongballs[4].y = 300; // normi sdl-looppi SDL_Event event; for (;;) { if ( SDL_PollEvent ( &event ) ) { if ( event.type == SDL_QUIT ) break; // siirrä hiirellä liikuteltavaa palloa phongballs[0].y = event.motion.y; phongballs[0].x = event.motion.x; } DrawScene(pSurface, &event); } SDL_FreeSurface(pSurface); return(0); }
Vaihtoehtoinen paletti
Uint32 pal[] = {16711680, 16713472, 16715520, 16717312, 16719104, 16720896, 16722944, 16724736, 16726528, 16728576, 16730368, 16732160, 16733952, 16736000, 16737792, 16739584, 16741632, 16743424, 16745216, 16747008, 16749056, 16750848, 16752640, 16754688, 16756480, 16758272, 16760064, 16762112, 16763904, 16765696, 16767744, 16769536, 16771328, 16773120, 16775168, 16776960, 16318215, 15859470, 15400725, 14941980, 14548770, 14090025, 13631280, 13172535, 12713790, 12255045, 11796300, 11337555, 10878810, 10485600, 10026855, 9568110, 9109365, 8650620, 8191875, 7733130, 7274385, 6815640, 6356895, 5963685, 5504940, 5046195, 4587450, 4128705, 3669960, 3211215, 2752470, 2293725, 1900515, 1441770, 983025, 524280, 65535, 63743, 61951, 60159, 58367, 56575, 54783, 52735, 50943, 49151, 47359, 45567, 43775, 41983, 40191, 38399, 36607, 34815, 33023, 30975, 29183, 27391, 25599, 23807, 22015, 20223, 18431, 16639, 14847, 13055, 11263, 9215, 7423, 5631, 3839, 2047, 255, 1016, 1777, 2282, 3043, 3805, 4566, 5071, 5832, 6593, 7354, 7859, 8620, 9381, 10143, 10648, 11409, 12170, 12931, 13436, 14197, 14958, 15719, 16224, 16986, 17747, 18508, 19013, 19774, 20535, 21296, 21801, 22562, 23324, 24085, 24590, 25351, 26112, 27136, 28160, 29184, 30464, 31488, 32512, 33536, 34560, 35584, 36608, 37632, 38912, 39936, 40960, 41984, 43008, 44032, 45056, 46336, 47360, 48384, 49408, 50432, 51456, 52480, 53760, 54784, 55808, 56832, 57856, 58880, 59904, 60928, 62208, 63232, 64256, 65280, 522247, 979214, 1436181, 1893148, 2350115, 2872619, 3329330, 3786297, 4243264, 4700231, 5157198, 5614165, 6071132, 6528099, 6985066, 7442033, 7899000, 8421504, 8878215, 9335182, 9792149, 10249116, 10706083, 11163050, 11620017, 12076984, 12533951, 12990918, 13447885, 13970389, 14427100, 14884067, 15341034, 15798001, 16254968, 16711935, 16711928, 16711921, 16711914, 16711907, 16711901, 16711894, 16711887, 16711880, 16711873, 16711866, 16711859, 16711852, 16711845, 16711839, 16711832, 16711825, 16711818, 16711811, 16711804, 16711797, 16711790, 16711783, 16711776, 16711770, 16711763, 16711756, 16711749, 16711742, 16711735, 16711728, 16711721, 16711714, 16711708, 16711701, 16711694, 16711687, 16711680};
Upea efekti. Itse en tosin SDL:ää osaa.
Tosi hieno :)
Uskomatonta, miten joku kykenee saamaan yksinkertaisesta taulukkosummausefektistä noin hitaan :) Vakiona pysyvä bittikartta lasketaan oikein neliöjuuren ja jakolaskun kanssa viisi kertaa framessa, minkä jälkeen vielä kehdataan väittää, että efekti oikeastikin vaatisi ylitehokkaan koneen.
Taulukkosummaustahan käytettiin paljon pc- ja amigademoissa noin kymmenen vuotta sitten. Metapallotyylisten efektien lisäksi tulee mieleen ainakin 2d-bumpmappi, jossa valobitmappia summataan bumpmapin päälle symmetrisellä paletilla (himmeä-kirkas-himmeä). Helppo, hieno ja siksi myös ylikäytetty temppu.
Ai niin, ja koodi muuten toimikoon myös varoittavana esimerkkiä siitä, millaista koodia syntyy, jos ei opettele C:tä ennen C++:aa. Tämä on käytännössä perus-C:tä, jossa on vain pari muuttujaa määritelty väärissä paikoissa ja jostain käsittämättömästä syystä inkludoitu iostream, jota ei edes käytetä mihinkään.
viznut kirjoitti:
Vakiona pysyvä bittikartta..
Tein tästä efektistä mahdollisimman sovellettavan, joten jätin mahdollisuuden liikuttaa kaikkia palloja. Kukaanhan ei niin typerä ole, että liikuttaisi aidossa sovelluksessa vain yhtä palloa. Vai onko? Phongkarttahan on periaatteessa vakio, mutta tästä on helposti tehtävissä yksinkertainen bumpmapperi - vain maaston pisteiden normaalit tulisi selvittää. Jos olisin ne laskenut etukäteen, bumpmapperiksi muuttaminen ei olisikaan enää niin helppoa.
viznut kirjoitti:
..että efekti oikeastikin vaatisi ylitehokkaan koneen.
Eikö 640 * 480 * 5 (1536000) kierroksen silmukka neliöjuuren kanssa sinusta vaadi tehokasta konetta? valokartan voisi toki laskea etukäteen, mutta alkuperäinen tavoitteeni olikin matkia erittäin tarkoin valon fysikaalista käyttäytymistä. (Tein ensiksi bumpmapperin ja koodi on suurimmaksi osaksi siitä kopioitua.) Itse en ainakaan tällä resoluutiolla ja viidellä valolla lähtisi millään 386:lla edes kokeilemaan. Entäs sinä? Iki-ihanina amiga-aikoina ei ehkä käytetty tällaisia resoluutioita, eikä valomääriä?
viznut kirjoitti:
Ai niin, ja koodi muuten toimikoon myös varoittavana esimerkkiä siitä, millaista koodia syntyy, jos ei opettele C:tä ennen C++:aa. Tämä on käytännössä perus-C:tä, jossa on vain pari muuttujaa määritelty väärissä paikoissa ja jostain käsittämättömästä syystä inkludoitu iostream, jota ei edes käytetä mihinkään.
Olisiko minun kenties pitänyt tehdä SDL:lle oma wrapperi luokista, jonka jälkeen tehdä yksinkertaisen struktuurin sijasta palloista luokka? Tulisihan koodista silloin selkeämpää ja oliopohjaisempaa, mutta ehkä tämä olisi hieman liioittelua tämän kokoiseen koodiin? Eikö olisi myös sekavaa määritellä kaikki muuttujat funktion alussa, kun ne voi c++:ssa keskellä koodiakin määritellä? Eikö c++ saa sinun mielestäsi muistuttaa c:tä? Onko käytettävä c++:n kaikkia hienoja ominaisuuksia? Olen itse ainakin vahvasti liikkeellä "yksinkertaisin on paras" -asenteella.
Iostreamin inkludointi oli vahinko, jonka huomasin ansiostasi. Kiitos huomautuksestasi, sekä rakentavasta kommentista.
Viznut se osaa sanoa mielipiteensä kiertelemättä =P
Hieno efekti.
Hieno efekti, mutta viznut osui kyllä aika oikeaan.
peki kirjoitti:
viznut kirjoitti:
Vakiona pysyvä bittikartta..
Tein tästä efektistä mahdollisimman sovellettavan, joten jätin mahdollisuuden liikuttaa kaikkia palloja. Kukaanhan ei niin typerä ole, että liikuttaisi aidossa sovelluksessa vain yhtä palloa. Vai onko? Phongkarttahan on periaatteessa vakio, mutta tästä on helposti tehtävissä yksinkertainen bumpmapperi - vain maaston pisteiden normaalit tulisi selvittää. Jos olisin ne laskenut etukäteen, bumpmapperiksi muuttaminen ei olisikaan enää niin helppoa.
Kyllä palloja voi liikuttaa vaikka käytettäisiin taulukkoa. Ideahan on siis se, että taulukkoon lasketaan yhden phong-kuvion arvot ja sitten kutakin palloa piirrettäessä haetaan arvot sieltä taulukosta pallon ja piirrettävän pisteen koordinaattien perusteella. Bumpmappauskin onnistuu helposti poikkeuttamalla taulukon indeksejä bumpmapin x ja y nousujen mukaan.
peki kirjoitti:
viznut kirjoitti:
..että efekti oikeastikin vaatisi ylitehokkaan koneen.
Eikö 640 * 480 * 5 (1536000) kierroksen silmukka neliöjuuren kanssa sinusta vaadi tehokasta konetta?
viznutin idea varmaan olikin, että tuossa efektissä ei oikeasti tarvitsisi laskea ajon aikana yhtään neliöjuurta.
Hyvin optimoiden siinä ei tarvitse laskea yhtään kerto tai jakolaskuakaan :). Kaikki työläs laskenta suoritettaisiin vain kerran ohjelman alussa laskemalla phong-kuvio taulukkoon.
peki kirjoitti:
Iki-ihanina amiga-aikoina ei ehkä käytetty tällaisia resoluutioita, eikä valomääriä?
Resuluutio oli varmaan yleensä hiukan pienempi, mutta valomäärä hyvinkin usein sama (256).
peki kirjoitti:
Olisio minun kenties pitänyt tehdä SDL:lle oma wrapperi luokista, jonka jälkeen tehdä yksinkertaisen struktuurin sijasta palloista luokka? Tulisihan koodista silloin selkeämpää ja oliopohjaisempaa, mutta ehkä tämä olisi hieman liioittelua tämän kokoiseen koodiin? Eikö olisi myös sekavaa määritellä kaikki muuttujat funktion alussa, kun ne voi c++:ssa keskellä koodiakin määritellä? Eikö c++ saa sinun mielestäsi muistuttaa c:tä? Onko käytettävä c++:n kaikkia hienoja ominaisuuksia? Olen itse ainakin vahvasti liikkeellä "yksinkertaisin on paras" -asenteella.
Idea varmaan oli, että yksinkertaiset koodit, jotka ei vaadi minkäänlaista oliomallia tai c++:n erikoisominaisuutta olisi hyvä kirjoittaa oikealla c:llä. Itse olen vähän samoilla linjoilla, mutta tietenkin, jos on tottunut kirjoittamaan kaiken c++:ksi niin eipä tuota kannata alkaa yhden koodivinkin takia muuttamaan.
hmm hieno hieno mutta varmaan voisi optimoida jotenkin
saisko noita __asm-juttuja mitenkään optimoitua pois? tuo dev-c++ pukkaa vaan erroria niistä.
saa, sen voi kommentoida ja ottaa neliöjuuri pois kommentista.
Aihe on jo aika vanha, joten et voi enää vastata siihen.