OpenGL/OpenGL:n käytäntöjä

Wikikirjastosta

Kuten jokainen hyvä ohjelmointikirjasto, OpenGL on suunniteltu yhtenäiseksi. Ymmärrettyään sen toimintaperiaatteen ohjelmoijan ei tarvitse muistaa jokaista yksityiskohtaa, sillä ne pystyy arvaamaan. Tämä luku esittelee OpenGL:ää opettaen samalla sen tärkeimpiä käytäntöjä.

OpenGL on tilakone[muokkaa | muokkaa wikitekstiä]

OpenGL:ää kutsutaan tilakoneeksi. Suuri osa komennoista ei varsinaisesti tee mitään; ne vain muuttavat OpenGL:n tilaa. Esimerkiksi glClearColor asettaa ruudun tyhjentämiseen käytettävän taustavärin.

glClearColor(r, g, b, a);

Parametrit annetaan RGBA-väriavaruudessa kaksoistarkkuuden liukulukuina välillä [0, 1]. Jos luku ei ole rajojen sisällä, se rajoitetaan automaattisesti (engl. clamping). Tyhjennysvärin oletusarvo on (0, 0, 0, 0).

Tilakoneen yhteydessä puhutaan usein nykyisestä tai senhetkisestä jostakin. Esimerkiksi glClear(GL_COLOR_BUFFER_BIT) tyhjentää ruudun senhetkisellä tyhjennysvärillä, joka toivottavasti on asetettu halutunlaiseksi glClearColor-funktiolla.

glClear(GL_COLOR_BUFFER_BIT);

Tyhjennysvärin ja oikeastaan minkä tahansa tila voidaan myös noutaa glGet-käskyllä:

double colors[4];
double r,g,b,a;
glGetDoublev(GL_COLOR_CLEAR_VALUE, colors);
r = colors[0];
g = colors[1];
b = colors[2];
a = colors[3];

Kaikki OpenGL:n määrittelemät funktiot alkavat kirjaimilla ’gl’, vakiot ’GL_’ ja tyypit ’GL’.

Piirtäminen[muokkaa | muokkaa wikitekstiä]

Piirtäminen aloitetaan komennolla glBegin(muoto) ja lopetetaan käskyllä glEnd(). Niiden välissä määritellään valitun geometrisen muodon nurkkapisteet glVertex-funktiolla:

glBegin(GL_TRIANGLES);
    glVertex3f(-1.0, -1.0, 0.0); /* vasen alakulma */
    glVertex3f(1.0, -1.0, 0.0); /* oikea alakulma */
    glVertex3f(0.0, 1.0, 0.0); /* keskellä ylhäällä */
glEnd();

Kolmas koordinaatti on z-akseli eli syvyys. Sen olisi voinut jättää pois käyttämällä glVertex-funktion toista muotoa:

glVertex2f(-1.0, -1.0);
glVertex2f(1.0, -1.0);
glVertex2f(0.0, 1.0);

Moni OpenGL-käsky on kuormitettu tällä tavalla. Numero tarkoittaa parametrien määrää ja sen jälkeen tuleva kirjain tyyppiä. OpenGL:n määrittelee omat tyyppinsä: ’f’ tarkoittaa tyyppiä GLfloat ja esimerkiksi ’dv’ GLdouble-taulukkoa (engl. GLdouble -vector).

glBegin- ja glEnd-komentojen välissä ei saa olla mitä tahansa OpenGL-käskyjä. Sallittuja ovat nurkkapisteisiin liittyvät tiedot kuten väri, materiaali, normaali ja pintakuvioinnin koordinaatti.

Tyypit[muokkaa | muokkaa wikitekstiä]

On tärkeää, että OpenGL-sovellus ja käyttäjän OpenGL-kirjasto ovat samaa mieltä muuttujien koosta ja esitysmuodosta muistissa. Epäselvyyksien välttämiseksi OpenGL määrittelee seuraavat tyypit:

Nimi Esitettävä datatyyppi Funktion pääte
GLbyte 8-bittinen etumerkillinen kokonaisluku b
GLshort 16-bittinen etumerkillinen kokonaisluku s
GLint, GLsizei 32-bittinen etumerkillinen kokonaisluku i
GLfloat, GLclampf 32-bittinen liukuluku f
GLdouble, GLclampd 64-bittinen liukuluku d
GLubyte, GLboolean 8-bittinen etumerkitön kokonaisluku ub
GLushort 16-bittinen etumerkitön kokonaisluku us
GLuint, GLenum, GLbitfield 32-bittinen etumerkitön kokonaisluku ui

Eri käyttöjärjestelmissä OpenGL-tyypit ja C-tyypit saattavat vastata toisiaan eri tavoin, joten on parasta käyttää OpenGL:n määrittelemiä tyyppejä tai huolehtia, että tyyppimuunnokset ovat turvallisia.

GLclampf- ja GLclampd-tyypit tarkoittavat, että OpenGL-funktio rajoittaa liukuluvut automaattisesti jollekin välille.

Koordinaatisto riippuu sen hetkisistä matriiseista[muokkaa | muokkaa wikitekstiä]

OpenGL ei oletusarvoisesti käytä tyypillistä pikseleihin perustuvaa koordinaatistoa. ”Kameran” eli OpenGL-näkymän vasen alakulma on piste (−1, −1) ja oikea yläkulma (1, 1). Akseli y osoittaa siis ylöspäin samalla tavalla kuin matematiikassa, ja origo on keskellä ruutua. Tätä voidaan kuitenkin muuttaa.

/* koordinaatiston rajojen muuttaminen */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(vasen, oikea, ala, ylä, lähi, kauko);

OpenGL käyttää matriisipinoja. Matriisi on kaksiulotteinen taulukko lukuarvoja. Niillä liikutetaan tehokkaasti suuria määriä pisteitä. Tehokkuus juontuu siitä, että liikutusoperaatioita voidaan ketjuttaa kertomalla matriiseja. Matriisipinoja on kolme eri tarkoituksiin, ja komento glMatrixMode valitsee nykyisen matriisipinon.

Projektiomatriisin (GL_PROJECTION) on tarkoitus esittää kameran linssiä. Todellisuudessa se vain liikuttaa pisteitä sopivalla tavalla. Käsky glLoadIdentity() asettaa nykyiseksi matriisiksi identiteettimatriisin, joka ei tee mitään. Sitä onkin hyvä lähteä kertomaan erilaisilla liikutusoperaatioilla. Komento glOrtho sopii kaksiulotteiseen grafiikkaan. Se kertoo nykyisen matriisin yhdensuuntaisprojektiomatriisilla, joka määrää näkyvän koordinaatiston rajat. Oikeasti sekin vain liikuttaa pisteitä. Lähi ja kauko ovat todellakin syvyyssuuntaiset rajat; tyypilliset arvot ovat −1 ja 1.

Matriisien muuttaminen vaikuttaa sen jälkeen määriteltyihin nurkkapisteisiin: Käskyn glVertex yhteydessä pisteen paikka muunnetaan sen hetkisillä projektio- ja asettelumatriisilla.

Matriiseihin, koordinaatistoihin ja pinoihin palataan vielä myöhemmin.

Tyypillinen OpenGL-ohjelman rakenne[muokkaa | muokkaa wikitekstiä]

/* tässä ohjelmassa taustaväri on aina musta */
void alustus()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
}

/* asettaa koordinaatiston pikseleihin perustuvaksi,
   jossa y-akseli osoittaa alaspäin */
void koon_muutos(int leveys, int korkeus)
{
    glViewport(0, 0, leveys, korkeus);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, (double) leveys, (double) korkeus, 0.0, -1.0, 1.0);
}

/* tyhjentää edellisen ja piirtää uuden kolmion */
void piirto()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    glBegin(GL_TRIANGLES);
        glVertex2f(-1.0, -1.0); /* vasen alakulma */
        glVertex2f(1.0, -1.0); /* oikea alakulma */
        glVertex2f(0.0, 1.0); /* keskellä ylhäällä */
    glEnd();
}

Huomautuksia[muokkaa | muokkaa wikitekstiä]

  • Tämä luku vain esitteli OpenGL:ää. Käsitellyt funktiot on määritelty OpenGL Reference Manualissa. Linkin opus on OpenGL:n versioon 1.1.
  • Funktiopääte ’dv’ tulee sanoista double vector, sillä yksiulotteinen taulukko on oikeastaan vektori.
  • GLU-kirjasto määrittelee yksinkertaisemman muodon glOrtho-komennosta: gluOrtho2D jättää syvyyteen liittyvät parametrit pois.
  • Jos GLUTin reshape-tapahtuman käsittelijää ei määrittele, kirjasto kutsuu aina automaattisesti funktiota glViewport.

Harjoituksia[muokkaa | muokkaa wikitekstiä]

  • Kokeile, miltä kolmio näyttää, kun sen kulmapisteet ovat eri värisiä.
  • Katso OpenGL-rajapinnan kuvauksesta, mitä glViewport tekee. Mitä tapahtuu ikkunaa venyttäessä, jos sen jättää pois?