Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: OpenGL tekstuurimatriisi sekoaa

Sivun loppuun

Pöytälamppu [31.12.2006 15:53:04]

#

Teenpä tässä tälläistä pientä 3D-hommelia ja eteeni hyppäsi täysin käsittämätön ongelma. Piirtäessäni aaltoja tekstuurimatriisi (kai) sekoaa ja se aiheuttaa taivaaseen täydellisen disco-efektin. Pilvet päättävät myös pillastua, ja ne muuttuvat pitkiksi viivoiksi. Paikansin ongelman veden aalto -piirtolistan luontiin. Ohessa koodia ja niiden vaikutukset.

//Piirto listaan
glNewList(Vesi_aalto_lista,GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, Vesi_texture);

//glHint(GL_FOG_HINT, GL_NICEST);
glDrawArrays(GL_QUAD_STRIP,                 0, AaltoVertekseja);
//glHint(GL_FOG_HINT, GL_FASTEST);

glDrawArrays(GL_QUAD_STRIP,   AaltoVertekseja, AaltoVertekseja);
glDrawArrays(GL_QUAD_STRIP, 2*AaltoVertekseja, AaltoVertekseja);
glEndList();

Yllä oleva koodi toimii oikein. Kuva

Jos muutan sen muotoon:

//Piirto listaan
glNewList(Vesi_aalto_lista,GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, Vesi_texture);

glHint(GL_FOG_HINT, GL_NICEST);
glDrawArrays(GL_QUAD_STRIP,                 0, AaltoVertekseja);
glHint(GL_FOG_HINT, GL_FASTEST);

glDrawArrays(GL_QUAD_STRIP,   AaltoVertekseja, AaltoVertekseja);
glDrawArrays(GL_QUAD_STRIP, 2*AaltoVertekseja, AaltoVertekseja);
glEndList();

Saadaan aikaan hieno disco-efekti, joka ei ole tavoite. Kuva

Disco myös katoaa ja tavoiteltu taivas palautuu jos kommentoin kaksi alinta glDrawArrays-komentoa.

//Piirto listaan
glNewList(Vesi_aalto_lista,GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, Vesi_texture);

glHint(GL_FOG_HINT, GL_NICEST);
glDrawArrays(GL_QUAD_STRIP,                 0, AaltoVertekseja);
glHint(GL_FOG_HINT, GL_FASTEST);

//glDrawArrays(GL_QUAD_STRIP,   AaltoVertekseja, AaltoVertekseja);
//glDrawArrays(GL_QUAD_STRIP, 2*AaltoVertekseja, AaltoVertekseja);
glEndList();

Onhan se disco "kaunis", mutta taivaasta se ei käy. Onko tähän ongelmaan mitään kunnollista selitystä tai ratkaisua, koska en haluaisi törmätä tähän ongelmaan enää uudestaan?
Ongelma on todettu kahdella eri koneella, joten näytönohjaimessa vika ei kai voi olla.

Tässä vielä yksi kuva tästä efektistä.

pieslice [03.01.2007 23:40:25]

#

Mitä ajat takaa tolla?

    glDrawArrays(GL_QUAD_STRIP,   AaltoVertekseja, AaltoVertekseja);
    glDrawArrays(GL_QUAD_STRIP, 2*AaltoVertekseja, AaltoVertekseja);

Onko sulla määritelty glVertexPointer jne... tai glInterleavedArrays ennen noita.
Vaikuttais siltä että luet muistista ohi sun vertex arrayn. Miksi edes käytät listaa arrayn piirtoon?
Mitä yrität tolla glHint(GL_FOG_HINT, xxxx) jutulla?

Pöytälamppu [04.01.2007 13:24:55]

#

glVertexPointer on viittaa taulukkoon joka on 9*AaltoVertekseja kokoinen. Itse en usko lukevani yli taulukosta, sillä veden aallot piirtyvät aivan oikein.

float VerteksiArr[AaltoVertekseja*3 *3];

//Tässä kohtaa täytän VerteksiArr

glVertexPointer  (3, GL_FLOAT,	0,VerteksiArr);

Käytän listaa, koska sitä on helppo kutsua, eikä minun tarvitse pitää VerteksiArr-taulukkoa muistissa. glHint-komennolla pyrin saamaan paremman sumun (pixel-perfect) tuolle ensimmäiselle glDrawArrays-komennolle (se piirtää itse aallot). Nuo kaksi alempaa glDrawArrays-komentoa ovat vähemmän tärkeitä (aaltojen reunat), joten niille riittää vertex-perfect sumu.

Tutkiessani miksi vain taivas muuttuu discoksi sain selville että disco-efekti muodostuu vain ja ainastaan vain jos GL_FOG on disabloitu. Miksi sumun disabloiminen vaikuttaa näin? Vain poistamalla glDisable(GL_FOG) -komennon ennen taivaan piirtoa sain taivaan toimimaan. Olen asettanut sumun alkamaan 300 yksikön päästä, jolloin sillä ei pitäisi mitään vaikutusta taivaan kupuun(taivas on puolipallo, jonka säde on 1 yksikkö), korkeitaan vain pilviin. Vaikutus silti näkyy taivaassa.

Testasin disabloida sumun (glDisable(GL_FOG)) ohjelman toisesta osasta, joka hoitaa ajoneuvojen piirron (nuolia, jotka liikkuvat viivoja pitkin). Tuloksena ajoneuvojen tekstuurin vääristymisen. Ennen Jälkeen

Jostain syystä sumun disabloiminen aiheuttaa tekstuurin vääristymisen, jos piirrän veden aallot eri laatuisilla sumuilla. Ilmeisesti ainoa ratkaisu on pirtää taivas (ja kaikki muukin) sumun kanssa, jos haluan piirtää osan vedestä laadukkaammalla sumulla. Tai piirtää vesi heikommalla sumulla, jotta voin piirtä taivaan ilman sumua.

pieslice [04.01.2007 18:54:31]

#

Miten määrittelet veden ja taivaan texture koordinaatit?

Pöytälamppu [04.01.2007 19:58:59]

#

Veden textuurikordinaatit lasketaan suoraan jakamalla vekteksin x- ja z-arvo 120:llä. Eli siis:

//Lasketaan texcoordit
for (int i=0;i<AaltoVertekseja*3;i++){
	TekstuuriArr[2*i+0] = VerteksiArr[3*i+0] / 120.0f;
	TekstuuriArr[2*i+1] = VerteksiArr[3*i+2] / 120.0f;
}

Piirron yhteydessä tekstuurimatriisia muutetaan vastaavasti ennen listan kutsumista. Näin veden tekstuuri näyttää pysyvän paikoillaan kameran liikkuessa. Siis että ei liiku mukana.

//Siirretään kameran kohtaan
glTranslatef(CAM_X,0,CAM_Z);

//Tekstuurimatriisin siirto
glMatrixMode(GL_TEXTURE);
//inv120 on 120:n vastaluku (n*inv120 = n/120)
glTranslatef(CAM_X*inv120,CAM_Z*inv120,0);
glMatrixMode(GL_MODELVIEW);

//Piirto

//Tekstuurimatriisin palautus
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);

Taivaan (puolipallo) tekstuurikordinaateissa x on aina 0 ja y lasketaan jakamalla puolipallon nykyinen kerros kerrosten lukumäärällä.

//Tämä lasketaan jokaiselle puolipallon pisteelle
texCoordit[addIndex][0] = 0;
texCoordit[addIndex][1] = y/float(vaakaTasoja)+0.01f;

Jokaisen pisteen texcoordin X on 0 tarkoituksella. Muutan teksuurimatriisia ennen piirtoa seuraavasti:

glMatrixMode(GL_TEXTURE);
glLoadIdentity();
//aika->timeOfDay on arvo väliltä 0-1
glTranslatef(aika->timeOfDay,0,0);

Näin saan helposti kellonajan mukaan muuttuvan taivaan. Olen ottanut mallia tuolta.

Outoa on että taivas toimii loistavasti jos pidän GL_FOG:in päällä taivaan piirron aikana, vaikka sen ei pitäisi vaikuttaa mitenkään tekstuurimatriisiin.

pieslice [04.01.2007 23:35:23]

#

ainakin sulla on [AaltoVertekseja*3 *3]; vertexiä joita vastaan on altoVertekseja*3 texture koordinaattia. oletko duplikoinut saman texcoord setin jokaiselle kolmelle Aaltoverteksejä quadstripille? (siis annatko niille saman texcoordpointterin). pistätkö texture koordinaatit arraylle glTexCoordPointerilla samaan aikaan kun laitat verteksit glVertexPointerilla? kokemuksesta voin sanoa että jos noi pointterit vertexarraylle ei ole oikein asetettu niin diskoahan se on.

tässä muutama hihasta vedetty pikaparannusehdotus.

//Siirretään kameran kohtaan
TÄHÄN OLIS HYVÄ LAITTAA glLoadIdentity();
glTranslatef(CAM_X,0,CAM_Z);

//Tekstuurimatriisin siirto
glMatrixMode(GL_TEXTURE);
TÄHÄN OLIS HYVÄ LAITTAA glLoadIdentity();


//inv120 on 120:n vastaluku (n*inv120 = n/120) > tollanen "optimointi" on tarpeeton nykykoneilla. sekottaa vaan koodin ymmärrystä

glTranslatef(CAM_X * (1.f/120.f),CAM_Z * (1.f/120.f) ,0); // >1.f/120.f kääntyy vakioksi, ja on selkeämpi lukea

*snip*

muutenkin suosittelisin käyttämään gluLookAt funktiota kameran translaatiossa. olisi muutenkin selkeämpää jos käyttäisit jotain Vector3-structia

struct Vector3
{
float x;
float y;
float z;
};

noiden float arrayiden sijaan vertexdatassa. se ajaa täsmälleen saman asian kuin float array ja on helpompi lukea.

muuten mikä näytönohjain sulla on käytössä? tämä voi olla ajuribugigin. itse on ole kyllä koskaan käyttänyt tuota glHint funkkaria fogin ohjaukseen. (epäilen sen hyötyä nykykorteilla...)

Metabolix [05.01.2007 10:42:26]

#

//inv120 on 120:n vastaluku (n*inv120 = n/120) > tollanen "optimointi" on tarpeeton nykykoneilla. sekottaa vaan koodin ymmärrystä

glTranslatef(CAM_X * (1.f/120.f),CAM_Z * (1.f/120.f) ,0); // >1.f/120.f kääntyy vakioksi, ja on selkeämpi lukea

Ja mitä vikaa on laittaa vain suoraan jakolaskuna tuo? Minusta se olisi vielä selkeämpi, ja jos tuollainen optimointi todella johonkin vaikuttaa, eiköhän kääntäjä sen hoida. Minulla näyttivät kerto- ja jakolaskut olevan yhtä nopeita, mitä nyt pari sataa miljoonaa toimitusta laitoin laskemaan.

Pöytälamppu [05.01.2007 14:27:59]

#

Tekstuuri kordinaatit on taulukossa joka on AaltoVertekseja*6 kokoinen, ja viittaan siihen vain kerran glTexCoordPointerilla.

float TekstuuriArr[AaltoVertekseja*2*3];

//Tässä lasketaan vekteksit

//Lasketaan texcoordit
for (int i=0;i<AaltoVertekseja*3;i++){
	TekstuuriArr[2*i+0] = VerteksiArr[3*i+0] / 120.0f;
	TekstuuriArr[2*i+1] = VerteksiArr[3*i+2] / 120.0f;
}

glTexCoordPointer(2, GL_FLOAT,	0,	TekstuuriArr);

Ongelmasta lisää:
Tein testin jossa poistin veden piirron kokonaan ja korvasin sen seuraavalla koodilla:

void Testaus(){
	glHint(GL_FOG_HINT,GL_NICEST);
	glCallList(testi_lista);
	glHint(GL_FOG_HINT,GL_FASTEST);
}

testi_lista sisältää 24 trianglea ja 84 quadsia, kummatkin piirretty glDrawArrays-komennolla, niille on määrätty glTexCoordPointer ja glNormalPointer.
Tulos: Taivas vääristyi osittain. Tähdet (teksturoitu quad) ja kuu (myös teksturoitu quad) vääristyivät. Pilvet eivät vääristyneet.

Löysin uuden tavan ratkaista ongelma.
Jos kutsun ennen tähtien piirtoa (teksuurimatriisille) glLoadIdentity, tähdet vääristyvät. Mutta jos kutsun glLoadIdentityn jälkeen glTranslatef(0,0,0) tähdet toimivat. Sama toimii kuun kanssa.

Siis koodina:

glMatrixMode(GL_TEXTURE);

glLoadIdentity();
//glTranslatef(0,0,0);
tahdet->Draw();


glTranslatef(aika->timeOfDay,0,0);
puolipallo->Draw();

glLoadIdentity();
//glTranslatef(0,0,0);
aurinko->Draw();

glLoadIdentity();
glTranslatef(aika->timeOfDay*pilvet->nopeus,0,0);

pilvet->Draw();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);

Jos nuo glTranslatef(0,0,0) -kohdat ottaa käyttöön taivas piirtyy oikein. Tekstuurimatriisi ei muutu, mutta tulos muuttuu. Outoa.

Näytönohjain on ATI Radeon 9700 ja ajurit ovat uusimmat.

Edit. Tuo glTranslatef(0,0,0) toimi vain tuon void Testaus() -jutun kanssa.


Sivun alkuun

Vastaus

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

Tietoa sivustosta