OpenGL/Matriisi 3d-grafiikassa

Moni kuvittelee, että 3d-grafiikkaan liittyvä matematiikka olisi monimutkaista. Sen kulmakivi on matriisi, jonka käyttäminen on hyvinkin suoraviivaista – suorastaan lineaarialgebraa. Muutamassa asiassa täytyy vain luottaa itseään viisampiin matemaatikoihin, jotka ovat ratkaisseet asiat ohjelmoijan puolesta.

Tämän luvun voi ohittaa, jos pienikin määrä matematiikkaa tuottaa harmaita hiuksia. Kannattaa kuitenkin kokeilla, sillä asia on helppolukuista.

Matriisi muokkaa

Matriisi on kaksiulotteinen taulukko. Koon m × n matriisi piirretään seuraavasti:

 

4×4-matriisit ovat hyödyllisiä 3d-grafiikassa, koska niillä voidaan liikutella nurkkapisteitä tehokkaasti. Liikuttelua kutsutaan muunnokseksi (engl. transformation) ja siihen soveltuvaa matriisia muunnosmatriisiksi (engl. transformation matrix). Muunnoksia voidaan ketjuttaa lukemattomia määriä, ja lopputulos on silti yksi ainoa 4×4-matriisi.

Muunnosmatriisien luokittelu muokkaa

Ehdottomasti tärkeimmät muunnosmatriisityypit ovat:

  • translaatiomatriisi, joka siirtää pisteitä johonkin suuntaan
  • rotaatiomatriisi, joka kiertää pisteitä origon kautta kulkevan akselin ympäri
  • skaalausmatriisi, joka suurentaa pistepilveä kertomalla niiden koordinaatit jollakin luvulla
  • projektiomatriisi, joka projisoi kolmiulotteiset koordinaatit kaksiulotteiselle näyttöruudulle

Jokainen ylläolevista kuuluu affiinikuvausten (engl. affine transformation) joukkoon, sillä:

  1. Jos kolme pistettä on samalla suoralla, ne ovat samalla suoralla myös affiinikuvauksen jälkeen.
  2. Kyseisten pisteiden etäisyyksien suhde säilyy.

Lisäksi kaikki paitsi translaatiomatriisi ovat lineaarikuvauksia (engl. linear transformation). Translaatiomatriisi ei nimittäin aina kuvaa origoa origoksi.

Muunnosmatriisien muodostamista käsitellään pintapuolisesti luvun lopussa. Tästä eteenpäin vain oletetaan, että se osataan tehdä – ja itse asiassa niin OpenGL osaakin.

Muunnosten ketjuttaminen on kertolaskua muokkaa

Muunnoksia voidaan ketjuttaa kertomalla muunnosmatriiseja erityisellä tavalla. Halutaan vaikkapa tehdä järjestyksessä seuraavat muunnokset:

  1. Kierretään pisteitä x-akselin ympäri −10 astetta.
  2. Liikutetaan pisteitä z-akselin suuntaan 5 yksikköä.
  3. Kierretään pisteitä y-akselin ympäri 5 astetta.

Tällöin kerrotaan muunnoksia vastaavat matriisit päinvastaisessa järjestyksessä:

M = M3 M2 M1

Lopputulos on hämmästyttävä: M sisältää kaikki muunnokset oikeassa järjestyksessä, vaikka siinä on yhä vain 4 × 4 lukua!

Muunnos on kertolasku muokkaa

Miten matriiseilla sitten muunnetaan pisteitä? Kuten voi arvata: Matriisi ja pisteen paikkavektori kerrotaan keskenään, jolloin tulos on muunnettu paikkavektori.

v' = M v

Nämä ”taianomaiset” matriisien kertolaskut ovat myös tehokkaita: Ne eivät tarvitse hitaita trigonometrisiä funktioita eivätkä edes jakolaskuja, vaan ainoastaan kertolaskuja. Tähän verrattuna matriisin muodostaminen voi olla hitaanpuoleista; onneksi matriisi tarvitsee muodostaa vain kerran kymmenistä tuhansista pisteistä koostuvalle 3d-mallille.

Vaikka OpenGL-ohjelmoijan ei varsinaisesti tarvitsekaan tietää matriisien kertolasku- tai muodostussääntöjä, perusteellisuuden vuoksi ne vielä esitellään luvun lopuksi.

Matriisien kertolasku muokkaa

Matriisien kertolaskusäännöt on ehkä helpointa muistaa vektorien pistetulon avulla. Olkoon A ja B kerrottavat matriisit. Ajatellaan, että matriisi A on sarake rivivektoreita; B on puolestaan rivi sarakevektoreita. (C-ohjelmointikielessäkin kaksiulotteinen taulukko muodostetaan sisäkkäisillä yksiulotteisilla taulukoilla!) Kertolaskun lopputulos saadaan pistetuloilla seuraavaan tapaan:

 

Pistetulo kun on määritelty vektoreille kaikissa ulottuvuuksissa:

a · b = a1 b1 + a2 b2 + ...

Matriisin ja vektorin kertolasku muokkaa

Matriisin ja vektorin kertolasku on matriisien kertolaskun erikoistapaus: vektoria ajatellaan matriisina, jossa on yksi sarake. Jotta pistetulo olisi mahdollinen, 4×4-matriisien kohdalla kolmiulotteiseen vektoriin täytyy lisätä uusi komponentti w = 1. Sitä käytetään hyväksi perspektiiviprojektiossa.