Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: C++: Phongipallot

Sivun loppuun

peki [04.10.2004 23:52:44]

#

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};

Juice [14.10.2004 19:29:38]

#

Upea efekti. Itse en tosin SDL:ää osaa.

Gwaur [14.10.2004 20:36:15]

#

Tosi hieno :)

viznut [14.10.2004 23:15:42]

#

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.

peki [15.10.2004 14:27:40]

#

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.

sooda [15.10.2004 15:16:56]

#

Viznut se osaa sanoa mielipiteensä kiertelemättä =P
Hieno efekti.

FooBat [15.10.2004 18:38:30]

#

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.

BlueByte [15.10.2004 20:34:42]

#

hmm hieno hieno mutta varmaan voisi optimoida jotenkin

Fisher [02.03.2005 14:38:58]

#

saisko noita __asm-juttuja mitenkään optimoitua pois? tuo dev-c++ pukkaa vaan erroria niistä.

ZcMander [10.06.2006 19:39:53]

#

saa, sen voi kommentoida ja ottaa neliöjuuri pois kommentista.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta