Juha-Pekka Jokela | jpjokela@surfeu.fi
Tinygl-kurssi, osat 1 ja 2

Tinygl on MorphOS:n opengl-yhteensopiva 3D-rajapinta, joka löytyy MorphOS:n versiosta 1.4 tai sitä uudemmista. Kurssi sopii kaikille, jotka ovat kiinnostuneita opengl-ohjelmoinnista.
Osa 1: Perusteet
Esimerkit on kirjoitettu tinygl:ää varten, mutta koodin pitäisi kääntyä (ehkä pienin muutoksin) mille tahansa alustalle, jolle löytyy opengl-tuki. Hyperionilta saadun tiedon mukaan OS4:ään olisi tulossa MESA-tuki (opengl-yhteensopiva 3D-rajapinta), mutta aikaisintaan lopulliseen versioon, ehkä myöhemmin. Esimerkkien pitäisi kääntyä ilman (suuria) muutoksia myös OS4:lle.

Mitä hyötyä opengl:n osaamisesta sitten on? Opengl on saatavilla useille eri alustoille, joten on suhteellisen helppoa kirjoittaa koodia, joka kääntyy ongelmitta niillä. Opengl:n suosiosta johtuen Internetistä löytyy paljon ilmaisia tutorialeja. Opengl-tuntemuksesta on myös hyötyä, jos aikoo portata opengl:ää käyttäviä pelejä muille alustoille (AmigaOS/MorphOS).

Uusimman version saa kysymällä tekijältä, Michal "Kiero" Wozniakilta. Kannattaa kysellä esim. IRC:n kautta nickiltä "kiero" kanavalta #morphos irc.freenode.net-palvelimella. Tinygl vaatii luonnollisesti näytönohjaimen, jolle on 3D-tuki. Tällä hetkellä ainoa vaihtoehto on Voodoo, mutta Radeon-tuki on tulossa.

Ensimmäisessä osassa tarkoituksenani oli tehdä "mahdollisimman yksinkertainen esimerkki, joka tekee jotain". Kaikkien funktioiden toimintaa ei selitetä vielä, mutta ehkä myöhemmissä osissa.


Uudet asiat: Piirtokäskyt, glTranslate, glRotate

glBegin()
Aloitetaan piirtäminen. Argumenttina annetaan tieto siitä, mitä piirretään, esim. GL_POINTS, GL_LINES, GL_TRIANGLES tai GL_QUADS. Kokeile vaihtaa GL_TRIANGLESin tilalle joku muu tyyppi. Huomioi myös se, muuttuuko tarvittavien pisteiden määrä!

glEnd()
Lopetetaan piirtäminen. Piirtäminen voidaan aloittaa uudestaan glBegin()-käskyllä. Piirtäminen täytyy lopettaa, jos esimerkiksi halutaan vaihtaa, mitä piirretään.

Huom! Kaikkia Opengl-funktioita ei saa suorittaa glBegin():n ja glEnd():n välissä! Osa taas täytyy!

glVertex()
Antaa yhden pisteen koordinaatit. Tarvittavien koordinaattien määrä riippuu siitä, mitä piirretään. 3 glVertex() -käskyllä voidaan esimerkiksi piirtää 3 pistettä tai 1 kolmio.

Huom! Tarkimmat lukijat varmaan huomaavat tässä vaiheessa, että koodissahan oli glVertex3f() eikä glVertex(). Kuten monelle muullekin käskylle, glVertex():lle voidaan antaa argumentit useassa eri muodossa, ja funktion nimen loppuosa määrää muodon, eli tässä tapauksessa 3 kpl float-tyyppisiä arvoja. Float-tyyppisiä arvoja käytetään ehkä eniten varsinkin, jos koordinaateille tehdään yhteen- ja vähennyslaskua monimutkaisempia laskutoimituksia.

glTranslate()
Siirtää origoa argumenttina annettujen arvojen verran.


glRotate()
Pyörittää koordinaatistoa argumenttien perusteella. Ensimmäinen argumentti määrää kulman. Pyöritys tapahtuu kolmen viimeisen argumentin määrittämän vektorin suhteen. Eli jos haluat pyörittää jonkun akselin suhteen, aseta sitä vastaava arvo ykköseksi ja muut nollaksi.


> Esimerkkikoodi

Sivun alkuun
Osa 2: Mennään metsään
Uudet asiat: ohjelmallinen mallinnus, valaistus, depth buffer, glEnable & glDisable, glPushMatrix & glPopMatrix

Ohjelmallinen mallinnus

Ohjelmallinen mallinnus tarkoittaa sitä, että objekti lasketaan matemaattisesti (mahdollisten argumenttien perusteella) sen sijaan, että se esimerkiksi ladattaisiin tiedostosta. Funktio "tree" piirtää kolmiulotteisen kuusen funktiolle annettujen argumenttien perusteella.
Argumentit:
seg: Määrittää, kuinka montaa polygonia käytetään esim. sylinterin piirtämiseen.
r1, r2, h1, h2: ks. kuva.

Valaistus
Valaistus otetaan käyttöön käskyllä glEnable(GL_LIGHTING). Lisäksi tarvitaan vähintään yksi valonlähde, valonlähde numero 1 otetaan käyttöön käskyllä glEnable(GL_LIGHT0). Valonlähteelle kannattaa määrittää myös sijainti, tämä onnistuu käskyllä glLightfv(GL_LIGHT0, GL_POSITION, light_pos). Valot lisäävät kolmiulotteiseen grafiikkaan syvyyttä. Valonlähteiden määrä kannattaa pitää mahdollisimman pienenä, koska jokainen uusi valonlähde hidastaa piirtämistä.

Depth Buffer
Depth Bufferin käyttöönotton liittyy muutamia vaatimuksia. Näyttöä alustettaessa täytyy ilmoittaa, että halutaan myös depth buffer. Tämä onnistuu lisäämällä "GLUT_DEPTH" glutInitDisplayMode()-funktion argumenttien joukkoon. Depth Buffer täytyy ottaa käyttöön glEnablella: glEnable(GL_DEPTH_TEST). Näytön tyhjentämisen yhteydessä myös Depth Buffer täytyy tyhjentää: glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT).

Depth Buffer lisää jokaiselle ikkunan pikselille "syvyysarvon". Jokaista pikseliä piirrettäessä lasketaan pikselin syvyys. Jos laskettu syvyys on pienempi, piirretään pikseli, ja korvataan vanha Depth Bufferin arvo uudella. Tämän ansiosta ei tarvitse huolehtia (poikkeuksia lukuunottamatta, totta kai) siitä, missä järjestyksessä polygonit piirretään. Poikkeuksena esimerkiksi läpinäkyvät polygonit: jos yrität piirtää pikseliä läpinäkyvänä piirretyn pikselin "taakse", ei sitä piirretä, koska Depth Bufferin arvo on suurempi. Tämän takia läpinäkyvät polygonit kannattaa piirtää viimeisenä.

glEnable ja glDisable
Käskyillä voidaan ottaa käyttöön tai poistaa käytöstä opengl:n ominaisuuksia. Argumenttina annetaan ominaisuus, jolle muutos tehdään. Esim. glEnable(GL_LIGHTING) ottaa valaistuksen käyttöön.

Huom! Voit muuttaa asetuksia milloin vain, paitsi glBegin():n ja glEnd():n välissä. Voit siis esimerkiksi piirtää osan kuvan polygoneista ilman valaistusta.

glPushMatrix ja glPopMatrix
glPushMatrix kopioi nykyisen matriisin pinoon, glPopMatrix taas palauttaa sen. Jos haluat esimerkiksi siirtää origoa väliaikaisesti kuten tässä ohjelmassa tehdään, laita siirtokäsky glPopMatrix():n ja glPushMatrix():n väliin. Koodissa voi toki olla useita sisäkkäisiä glPushMatrix()-kutsuja, mutta jokaista kohden pitäisi olla yksi glPopMatrix().

Esimerkkikoodi
Makefile kahdelle ensimmäiselle osalle

Lisätietoja:
> Listaus opengl-käskyistä ja yksinkertaiset selostukset niiden toiminnasta
>
Paljon opengl-tutorialeja

Seuraavat osat:
- Display listit
- Varjostus

Ehdotuksia, toivomuksia ja kysymyksiä voi lähettää osoitteeseen jpjokela@surfeu.fi.

Sivun alkuun