Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: SDL "hyytelö"

Sivun loppuun

kayttaja-3842 [24.06.2007 02:03:18]

#

Joo eli tuli tässä vaan mieleen, että miten olisi hyvä tapa toteuttaa SDL:llä "hyytelö kuva"? Eli siis ensiksi ladataan joku kuva ja se hilluisi ruudulla kuin hyytelö. :D Eli venyilisi vähän eripuolilta kokoajan. :D

pieslice [24.06.2007 04:01:09]

#

OpenGL:lä; laitat sen (2D) gridiin, mihin teksturoit kuvan ja animoit verteksejä.

kayttaja-3842 [24.06.2007 12:33:34]

#

Nytten oli lähinnä tarkoitus saada tämä toteutettua täysin SDL:llä.

Tzaeru [24.06.2007 14:06:36]

#

No, arvailtuani hetken mitä "hyytelö kuva" voi mahdollisesti oikein tarkoittaa, tulin sellaiseen johtopäätökseen, että se voisi olla jotakin jota edes etäisesti erilaisilla sinini-virityksillä heiluva kuva muistuttaisi.

Periaatteessa voit siis leikkiä, että ko. kuva on sini-aalto, jonka aallonpituus on kyseisen kuvan korkeus ja sen jälkeen siirtää jokaista kuvan pikseliä vaikka vasemmalle yhtä paljon kuin millä kohdalla sini-aalto olisi kyseisellä korkeus-akselin kohdalla.

Esim. pseudo-koodina, joka luultavasti muistuttaa omassa tapauksessani hiukan C:tä:

for (x = 0; x < kuvan_leveys; x++) // kunnes leveys-suunnassa kaikki pikselit läpi
{
  i = 0 // aina kun siirrytään leveys-suunnassa, nollataan i ja aina kun siirrytään korkeus-akselia pitkin, lisätään i:tä arvolla, joka on yhtä kuin 6.28 (huom. Pii kertaa kahden likiarvo) jaettuna kuvan korkeudella. Täten joka kerta saman korkeus-suunnan pikseliä siirretään yhtä paljon, jolloin, toivottavasti, kuva näyttäisi siltä, että se heiluisi leveyssuunnassaan.
  for (y = 0; y < kuvan_korkeus; y++) // Kunnes korkeus-suunnassa kaikki pikselit läpi
  {
     i =+ 6.28 / kuvan_korkeus; //
     piirra_pikseli(y, x =+ cos(i)); // cosinin avulla saadaan kuvan siirtymästä sini-aallon mallinen. Toivon.
  }
}

Olen vähän huono näissä sanallisissa selityksissä (ja luultavasti yhtä huono matemaattisissakin), mutta toivottavasti tuosta oli edes jonkinlaista hyötyä; Sini-aalloista (käytin tässä cos-funktiota saadakseni kivemmin arvon. Cosilla radiaani 0 ja 6.28 antavat saman arvon, yhden, jonka aikana funktion arvo ehtii vaihdella ensin positiiviesta ykkösestä(1) negatiiviseen ykköseen(-1) ja siitä taas positiiviseen ykköseen(1)) löytää myös asiaa wikistä ja koodivinkeissä on varmasti hyödyllisiä juttuja.

Tulisi myös huomata, että on jossakin määrin asiallista mahdollisuuksien mukaan miettiä optimointia tälläisille. Isossa kuvassa vähän väliä jokaisen pikselin läpikäynti vieläpä trigonometristen funktioiden kanssa voi käydä raskaaksi, varsinkin, jos kuvan on tarkoitus nopeasti heilua. Hyviä optimointivinkkejä, jotka eivät kuitenkaan liikaa sotke koodin selkeyttä, on esim. pistää halutut cosin arvot taulukkoon.

pieslice [24.06.2007 14:21:07]

#

Tee sama meshdeformaatio, mutta korvaat vaan OpenGL rendauksen omalla softatrianglefillerillä. Affine-teksturemapping riittänee, jos kuvan on tarkoitus warppia. Algoritmi on melko helppo.

kayttaja-3842 [24.06.2007 15:38:06]

#

Kiitosta, tuolla saan sen tehtyä! :D
--------------------------------------------
Edit1: Yki juttu vielä, että mites voin ottaa Uint32 tyyppisestä muuttujata arvot kokonaisluku muuttujiin? Eli Uint32 vari varit otetttaisiin int r,g,b; muuttujiin.

pieslice [24.06.2007 16:44:49]

#

Bittiaritmetiikalla.

Riippu tietysti onko värit koodattu RGB vai BGR formaatissa...

BGR formaatissa menee näin:

unsigned int r,g,b;
r = vari & 0x000000ff; //ANDilla maskataan siis bittejä pois.
g = (vari & 0x0000ff00) >> 8; //sama mutta siirretään vähän että saadaan arvo väliltä 0...255
b = (vari & 0x00ff0000) >> 16; //well..

Jos näyttää kummalliselta, niin sitten värikoodaus on väärin ja vaan vaihdat komponetteja päikseen.
Jos alphakanava on, niin se on sitten vikat 8 bittiä Axxx väriformaatissa tai ekat 8 bittiä xxxA väriformaatissa.

T.M. [24.06.2007 17:15:59]

#

RGB:

r = (vari >> 16) & 255;
g = (vari >> 8) & 255;
b = vari & 255;

Hmm, toi taitaa kyllä olla ARGB.

kayttaja-3842 [26.06.2007 15:01:04]

#

Aika outo juttu, mutta onko tosiaankin niin, että math.h sisältämä cos ja sin funktiot ovat niin hitaita, että ne saavat ohjelmani jumiin? Eli kun yritin laittaa pixeleitä pyörimään 1 asteisen kulmaan, niin ohjelma jumitti, mutta jos taas laitoin kulmaksi 0,niin kuva piirtyi ruudulle aivan normaalisti, ilman että ohjelma jumitti.

Eli

  lukitsepinta(naytto);
for (int x = 0; x < kuva->w; x++)
  for (int y = 0; y < kuva->h; y++)
  {


     g = OtaPixelivari(kuva,x,y);

     int r = (g >> 16) & 255;
     int g = (g >> 8) & 255;
     int b = g & 255;

     int tulo = ((255*3) - ((255 - r) + (255 - g) + (255 - b))) / 3;

        int xn = x * cos(1) - y * sin(1);
        int yn = x * sin(1) + y * cos(1);

        x = xn;
        y = yn;



     piirrapixeli(naytto,x,y,paletti[tulo]);
  }



}
  avaapinta(naytto);

Tässä ohjelma jumittaa

int xn = x * cos(1) - y * sin(1);//eli cos ja sin kulma = 1;
int yn = x * sin(1) + y * cos(1);

x = xn;
y = yn;

Tässä ohjelma ei jumitu ja kuva piirretään ruudulle normaalisti

int xn = x * cos(0) - y * sin(0); //eli cos ja sin kulma = 0;
int yn = x * sin(0) + y * cos(0);

x = xn;
y = yn;

T.M. [26.06.2007 21:06:15]

#

     g = OtaPixelivari(kuva,x,y);

     int r = (g >> 16) & 255;
     int g = (g >> 8) & 255;
     int b = g & 255;

Pisti heti silmään tuo muuttuja "g", jota ensiksi käytät, ja sitten vasta määrittelet, ihmettelen miten tuo menee kääntäjästä edes läpi o_O
Ja tuossa asetat vieläpä kaksi kertaa saman muuttujan, tuo "b" muuttuja käyttää tuota muuttunutta "g" muuttujaa jonka muutit aikaisemmalla rivillä...

Näin se pitäisi tehdä mielummin:

     vari = OtaPixelivari(kuva,x,y);

     r = (vari >> 16) & 255;
     g = (vari >> 8) & 255;
     b = vari & 255;

ja ennen noita muuttujien käyttöä ne pitäisi määritellä, älä määrittele muuttujia vasta silmukoiden sisällä.

Ohjelma taitaa hidastua tuon rivin takia:

        x = xn;
        y = yn;

Sillä nyt nuo for silmukat saattavat jäädä ikuiseen silmukkaan, tai juurikin hidastaa sitä ohjelmaa. Syy on se että annat for silmukoiden laskureille uusia arvoja, jolloin ne saattavat jopa jäädä pyörimään loputtomasti, kun ne eivät koskaan pääse siihen asti johon niiden pitäisi päästä.

Käytä rohkeasti uusia muuttujanimiä.

kayttaja-3842 [26.06.2007 23:49:38]

#

Tosiaankin, laitoin laitoin vahingossa 2 kertaa saman nimisen muuttujan (nytten nolottaa). Noh, vahinkoja sattuu. :D

Nytten kuvan "hyytelöminen" toimii suhtkoht hyvin paitsi että kuvassa näkyy ikäniä mustia viivoja. Mistä tämä voisi johtua? Itselleni tuli mieleen, että pikselin kokoeinen väli tulee siitä, että vasemmalla olevia pixeleitä siiretään vasemmalle jolloin oikealla olevia ei ole vielä keretty siirtää vasemmalle josta syystä sitten kuvassa näkyy ikäviä mustia viivoja.

Kuva: http://img530.imageshack.us/img530/9853/mviivatgy8.jpg

for (int x = 0; x < kuva->w; x++){

  for (int y = 0; y < kuva->h; y++)
  {


     varikea = OtaPixelivari(kuva,x,y);

     //int r = (varikea >> 16) & 255;
     //int g = (varikea >> 8) & 255;
     //int b = varikea & 255;

     //int tulo = ((255*3) - ((255 - r) + (255 - g) + (255 - b))) / 3;

     h[0] = OtaPixelivari(kuva,x-1,y-1);
     h[1] = OtaPixelivari(kuva,x,y-1);
     h[2] = OtaPixelivari(kuva,x+1,y-1);
     h[3] = OtaPixelivari(kuva,x-1,y);
     h[4] = OtaPixelivari(kuva,x+1,y);
     h[5] = OtaPixelivari(kuva,x-1,y+1);
     h[6] = OtaPixelivari(kuva,x,y+1);
     h[7] = OtaPixelivari(kuva,x+1,y+1);

     j[0] = (h[0] >> 16) & 255;
     j[1] = (h[1] >> 16) & 255;
     j[2] = (h[2] >> 16) & 255;
     j[3] = (h[3] >> 16) & 255;
     j[4] = (h[4] >> 16) & 255;
     j[5] = (h[5] >> 16) & 255;
     j[6] = (h[6] >> 16) & 255;
     j[7] = (h[7] >> 16) & 255;

     int varikarvo = (j[0] + j[1] + j[2] + j[3] + j[4] + j[5] + j[6] + j[7]) / 8;

     i += 6.28 / kuva->h;



     piirrapixeli(naytto,xn =+ x + cos(i)+300,y+200,paletti[varikarvo]);
  }



}

pieslice [27.06.2007 02:01:29]

#

Vaikuttaa pyöristysvirheeltä?!

T.M. [27.06.2007 19:49:33]

#

Luulen että tuo paletti on liian pieni, ja ottaa arvoja taulukon ulkopuolelta, joka ei ole kovin terveellistä.

kayttaja-3842 [28.06.2007 17:15:27]

#

T.M. kirjoitti:

Luulen että tuo paletti on liian pieni, ja ottaa arvoja taulukon ulkopuolelta, joka ei ole kovin terveellistä.

Muokkasin koodia niin, että väri arvo ei voi mennä yli 255 eikä alle 0, mutta muutosta ei tapahtunut. Paletin kyllä pitäisi olla riittävän suuri.

if( varikarvo > 255){varikarvo = 255;}
 if( varikarvo < 0){varikarvo = 0;}

(Mod. Edit. Järki mukaan: jos lisäät koodiin kaksi riviä, älä laita koko koodia tänne uudestaan!)

Paletti:

Uint32 paletti[] = {0, 327680, 720896, 1048576, 1376256, 1769472, 2097152, 2424832, 2818048, 3145728,
3473408, 3801088, 4194304, 4521984, 4849664, 5242880, 5570560, 5898240, 6291456, 6619136, 6946816, 7340032,
7667712, 7995392, 8388608, 8716288, 9043968, 9371648, 9764864, 10092544, 10420224, 10813440, 11141120,
11468800, 11862016, 12189696, 12517376, 12910592, 13238272, 13565952, 13959168, 14286848, 14614528,
14942208, 15335424, 15663104, 15990784, 16384000, 16711680, 16712192, 16712704, 16713216, 16713984,
16714496, 16715008, 16715520, 16716032, 16716544, 16717312, 16717824, 16718336, 16718848, 16719360,
16719872, 16720384, 16721152, 16721664, 16722176, 16722688, 16723200, 16723712, 16724224, 16724992,
16725504, 16726016, 16726528, 16727040, 16727552, 16728320, 16728832, 16729344, 16729856, 16730368,
16730880, 16731392, 16732160, 16732672, 16733184, 16733696, 16734208, 16734720, 16735488, 16736000,
16736512, 16737024, 16737536, 16738048, 16738560, 16739328, 16739840, 16740352, 16740864, 16741376,
16741888, 16742656, 16743168, 16743680, 16744192, 16744704, 16745216, 16745728, 16746496, 16747008,
16747520, 16748032, 16748544, 16749056, 16749568, 16750336, 16750848, 16751360, 16751872, 16752384,
16752896, 16753664, 16754176, 16754688, 16755200, 16755456, 16755712, 16755968, 16756224, 16756480,
16756736, 16757248, 16757504, 16757760, 16758016, 16758272, 16758528, 16758784, 16759040, 16759296,
16759552, 16759808, 16760064, 16760320, 16760832, 16761088, 16761344, 16761600, 16761856, 16762112,
16762368, 16762624, 16762880, 16763136, 16763392, 16763648, 16763904, 16764416, 16764672, 16764928,
16765184, 16765440, 16765696, 16765952, 16766208, 16766464, 16766720, 16766976, 16767232, 16767488,
16767744, 16768256, 16768512, 16768768, 16769024, 16769280, 16769536, 16769792, 16770048, 16770304,
16770560, 16770816, 16771072, 16771328, 16771840, 16772096, 16772352, 16772608, 16772864, 16773120,
16773376, 16773632, 16773888, 16774144, 16774400, 16774656, 16774912, 16775424, 16775680, 16775936,
16776192, 16776448, 16776704, 16776960, 16776965, 16776970, 16776976, 16776981, 16776986, 16776991,
16776996, 16777002, 16777007, 16777012, 16777017, 16777022, 16777028, 16777033, 16777038, 16777043,
16777048, 16777054, 16777059, 16777064, 16777069, 16777074, 16777080, 16777085, 16777090, 16777095,
16777101, 16777106, 16777111, 16777116, 16777121, 16777127, 16777132, 16777137, 16777142, 16777147,
16777153, 16777158, 16777163, 16777168, 16777173, 16777179, 16777184, 16777189, 16777194, 16777199,
16777205, 16777210, 16777215, 0};

Metabolix [28.06.2007 18:38:24]

#

Mikä ihme tämä on:
xn =+ x + cos(i)+300
Jos tarkoitat, että xn = xn + x + cos(i)+300, niin hakemasi operaattori on +=.

T.M. [29.06.2007 02:04:22]

#

Koitappas vaihtaa palettia? Tuossa kun on viimeisenä arvona musta, mutta toisiksiviimeisenä valkoinen... jotenkin ei näytä hyvältä paletilta. Vähän kyllä nyt epäilen ettäkö se paletista edes johtuisi...

kayttaja-3842 [29.06.2007 10:47:19]

#

Metabolix kirjoitti:

Mikä ihme tämä on:
xn =+ x + cos(i)+300
Jos tarkoitat, että xn = xn + x + cos(i)+300, niin hakemasi operaattori on +=.

Joo tuo xn oli myös periaatteessa ihan turhaasiellä. :D


muokkasin sen nytte näni:

piirrapixeli(naytto,x + cos(i)+300,y+200,paletti[varikarvo]);

T.M. kirjoitti:

Koitappas vaihtaa palettia? Tuossa kun on viimeisenä arvona musta, mutta toisiksiviimeisenä valkoinen... jotenkin ei näytä hyvältä paletilta. Vähän kyllä nyt epäilen ettäkö se paletista edes johtuisi...

Ei se minusta tuosta paletista kyllä johdu, mutta mitä ehdotat paremmaksi paletiksi?

Metabolix [29.06.2007 11:44:49]

#

Kuulepa, opettele vähän itse debugaamaan. Laita tuohon ennen piirrapixeli-kutsua jotain (printtaus tai mieluummin ehkä ihan oikeita debug-wathceja) ja katso, saako tuo x:lle antamasi lauseke koskaan tuota tiettyä arvoa, jossa nyt näkyy musta pikseli. Jos ei, niin siitä voit sitten lähteä taaksepäin tutkimaan, miksei saa.


Sivun alkuun

Vastaus

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

Tietoa sivustosta