OpenGL:n perusteet Osa 4: Valot ja varjot
|
|
- Merja Penttilä
- 8 vuotta sitten
- Katselukertoja:
Transkriptio
1 OpenGL:n perusteet Osa 4: Valot ja varjot OpenGL on käyttöjärjestelmäriippumaton kirjasto 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen. Esimerkeissä käytetään C\C++ kieltä. Tämä on artikkelisarjan viimeinen osa. 1 Valaistuksen matematiikkaa Oikeassa elämässä näkemämme kuva syntyy, kun jostakin valonlähteestä lähtevä valo heijastuu jostakin pinnasta silmämme verkkokalvolle. Voisimme siis teoriassa laskea virtuaalimaailmassa olevan kappaleen valaistuksen sinkoamalla virtuaalisesta valonlähteestä miljardeittain valonsäteitä ja laskemalla mitkä niistä osuvat renderöimäämme pintaa. Tätä kutsutaan termillä "photon mapping" ja jotkin 3Dmallinnusohjelmat itseasiassa käyttävät tätä menetelmää photorealisten kuvien renderöintiin. Miljardien valonsäteiden radan laskeminen ei kuitenkaan sovi realiaikasovellukselle. Ajutus voidaan tietenkin kääntää päälaelleen. Jäljitetään pinnan jokaisesta pikselistä valonsäteen rataa nurinkurisesti ja katsotaan johtaako se valonlähteeseen. Tätä menetelmää kutsutaan termillä "ray tracing". Tekniikka on huomattavasti kevyempi ja sitä käyttäviä demoja on muutamia, mutta myös tämä tekniikka on vielä liian raskas varsinkin peleille. Vasemmalla ilman valoja. Keskellä valojen kanssa ja oikealla myös varjot mukana. Huomaa lisääntynyt realismi. Koska emme voi laskea valon vaikutusta täydellisen tarkasti, täytyy meidän löytää jokin keino arvioida sitä. Uskottavan valaistuksen aikaansaamiseksi voimme jakaa pinnasta verkkokalvolle saapuvan valon karkeasti neljään eri tyyppiin: ympäristövaloihin (ambient light), hajavaloihin (diffuse light), peiliheijastukseen (specular light) ja itsesäteiltyyn valoon (emissive light).
2 1.1 Hajavalo Hajavalo on valoa, joka tulee suoraan jostakin valonlähteestä pintaan. Pinta absorboi osan tästä valosta ja heijastaa loput eteenpäin silmän verkkokalvolle. Merkitsemme hajavaloa tässä artikkelissa symbolilla D (niin kuin diffuse). Hajavalon määrä on riippuvainen siitä kulmasta, jossa valonsäde saapuu pintaan. Jos L (niin kuin light) on vektori kohti valonlähdettä ja N (niin kuin normal) pinnan normaalivektori ja kummankin näiden vektorien pituus on yksi, niin hajavalon määrä saadaan näiden pistetulona eli N L. Pinta ei kuitenkaan heijasta valon kaikkia aallonpituuksia tasapuolisesti, vaan se absorboi osaa paremmin ja osaa huonommin. Tästa muodostuu pinnan väri. Esim. jos pinta absorboi kaiken muun paitsi punaisen valon näyttää pinta punaiselta. Kaiken lisäksi pintaan saapuva valo ei välttämättä ole valkoista eli sisällä kaikkia mahdollisia aallonpituuksia. Meidän tarvitsee siis kertoa hajavalo vielä pinnan värillä, jota merkitsemme symbolilla C d (niin kuin color ja decal) ja valon värillä, jota merkitsemme symbolilla C l (niin kuin color ja light). Niinpä saamme hajavalon lopulliseksi yhtälöksi: C d * C l * ( N L ). Tässä * ei siis tarkoita pistetuloa vaan värien kertomista komponenteittain. 1.2 Ympäristövalo Ympäristövalo on valoa, jonka ei voida sanoa tulevan mistään tietystä suunnasta ja se vaikuttaa kaikkiin pintoihin samalla tavalla, olkoot ne sitten missä asennossa tahansa suhteessa valonlähteeseen. Tämä johtuu siitä, että valonsäteet kimpoilevat pinnasta toiseen sekoittuen lopulta yhteinäiseksi tasaiseksi valoksi. Merkitsemme tässä artikkelissa ympäristövaloa symbolilla A (niin kuin ambient). Ympäristävalon määrä on koko ajan vakio ja sitä ei oikein voi laskea mitenkään, vaan se sen määrä on arvioitava. Jos minimi on 0 ja maksimi 1, niin realistinen kuva saadaan yleensä hyvin pienillä arvoilla esim 0.1. Koska pinta heijastaa myös ympäristövalosta vain tietyt aallonpituudet, täytyy se kertoa pinnan värillä, joilloin saamme tälle komponentille yhtälön: C l * A. 1.3 Peiliheijastus Kun valo osuu pintaan tietyssä kulmassa, ei pinta absorboikkaan yhtään valoa vaan heijastaa sen sellaisenaan eteenpäin. Kutsumme tällaista valoa peiliheijastuneeksi ja merkitsemme sitä symbolilla S (niin kuin specular). Peiliheijastuksen kulma riippuu
3 pinnan materiaalista, kutsumme tätä ominaisuutta pinnan kiiltävyydeksi ja merkitsemme sitä symbolilla G (niin kuin gloss). Lisäksi tähän vaikuttaa pinnan tasaisuus, jota merkitsemme symbolilla M, realistinen M:n arvo on yleensä välillä Peiliheijastus riippuu valonlähteen sijainnin lisäksi myös siitä mistä kulmasta pintaa katsellaan. Meidän tarvitsee tietää siis vielä vektori, joka osoittaa kohti kameraa. Merkitsemme tätä vektoria symbolilla E (niin kuin eye). Peiliheijastuksen laskemiseeen on kaksi tapaa: ns phong- ja blinn-valaistusmallit. Phong-mallissa meidän tarvitsee tietää vektori R (niin kuin reflection), joka saadaan kun vektori E peilataan vektorin N suhteen. Tämä tehdään kaavalla: R = 2 * (N L) * N - L. Kun R on tiedossa saadaan peiliheijastus kaavasta C l * G * (L R)^M. Eli valon väri kertaa G kertaa L:n ja R:n pistetulo potenssiin M. Pinnan väri ei siis vaikuta peiliheijastukseen. Vektorin R laskeminen on kuitenkin hieman turhan monimutkainen. Tämän takia on olemassa yksinkertaisempi malli Blinn. Blinn-mallissa vektoria R ei tarvita, vaan lasketaan vektori H, joka puolittaa vektoreiden L ja E välisen kulman. Tähän jälkeen peiliheijastus lasketaan yhtälöstä: C l * G * (N H)^M.
4 Potenssilasku ^M kuitenkin muodostaa pienen ongelman. Potenssiin korotus nimittäin on kaikesta nykyajan laskentatehosta huolimatta varsin hidas operaatio varsinkin kun se joudutaan laskemaan, jopa tuhansia kertoja per frame. Tämän takia saattaa joskus olla järkevää lukita M arvoon 16 ja aproksimoida funktiota x^16, jollakin toisella yksinkertaisemmalla funktiolla. Tällaisia ovat mm: max( 0, 4*(x-0.75) ) ja max( 0, 4*(x*x-0.75) ). 1.4 Itsesäteilty valo Viimeinen muoto on itsesäteilty valo. Tämä on valoa, jota pinta itse tuottaa. Tyypillinen itsevalaiseva pinta on fosfori. Merkitsemme tätä valoa symbolilla E (niin kuin emissive). Tätäkään valoa ei voida mitenkään laskea vaan se on arvioitava. Tavallisilla pinnoilla tämä se on yleensä 0. Jos oletamme, että pinta säteilee itsensä väristä valoa saamme tämän komponentin kaavaksi: C d * E. 1.5 Lopullinen valoyhtälö Nyt voimme muodostaa yhtälön, joka antaa meille hyvin realistisen valaistuksen. Laskemme vain eri muodot yhteen eli kokonaisvalo, jota merkitsemme symbolilla I (niin kuin illumination) on A+D+S+E. Jos vielä puramme yhtälön auki blinn-mallin mukaisesti saamme I = C d * A + C d * C l * ( N L ) + C l * G * ( N H ) ^ M + C d * E. Tämä ei ota vielä huomioon sitä tosiasiaa, että valon kirkkaus vaimenee mitä kauempana valonlähteestä ollaan. Yhtälö pitää siis kertoa vaimennustermillä, joka saadaan jakamalla 1 jollakin sopivalla vakiolla k kerrottuna etäisyyden (käytämme symbolia d) neliöllä eli 1/(k*d^2). Tämä olisi siis fysikaalisesti oikein, mutta ei välttämättä hyvän näköinen. Niinpä usein käytetään jotain muuta vaimennus termiä esim: max( 0, 1 - ( d / r )^2 ). Tällöin valon kirkkaus on maksimissaan keskellä valonlähdettä ja hiipuu nollaan saavutettaessä etäisyys r ja on nolla kaikkialla tätä kauempana. Lopullinen (blinn-mallin mukainen) yhtälö on siis: I = 1/(k*d^2) * ( C d * A + C d * C l * ( N L ) + C l * G * ( N H ) ^ M + C d * E ).
5 Jos valonlähteitä on useampia pitää valaistus laskea kaikille valoille erikseen ja sitten summata tulokset. 2 Käytännön toteutus Nyt siis tiedämme valaistukseen tarvittavan yhtälön. Mutta kuinka kappale sitten oikein valaistaan sillä? Helpposti, lasketaan yhtälö kappaleen jokaiselle verteksille ja annetaan tulos värinä OpenGL:lle glcolor3f()-funktiolla. Tehdään seuraavaksi funktio, joka laskee tämän valoyhtälön syötteenään saamalle verteksille. Se saa syötteenään verteksin sijainnin (Pv), valon sijainnin (Pl), pinnan värin (Cd), valon värin (Cl) ja pinnan normaalin (N). Funktio laskee verteksille valon ja antaa sen OpenGL:lle värinä. Yksinkertaisuuden vuoksi se jättää vaimenemisen huomiotta ja olettaa itsesäteillyn valon olevan nolla. void valo(float Pv[3], float Pl[3], float Cd[3], float Cl[3], float N[3]) const float A=0.1; const float G=0.9; const float M=16; float L[3], E[3], H[3], I[3]; float temp; // Laske vektori L, joka osoittaa kohti valoa. L[0]=Pl[0]-Pv[0]; L[1]=Pl[1]-Pv[1];
6 L[2]=Pl[2]-Pv[2]; temp=sqrt(l[0]*l[0]+l[1]*l[1]+l[2]*l[2]); L[0]/=temp; L[1]/=temp; L[2]/=temp; // Laske vektori E, joka osoittaa kohti kameraa. E[0]=-Pv[0]; E[1]=-Pv[1]; E[2]=-Pv[2]; temp=sqrt(e[0]*e[0]+e[1]*e[1]+e[2]*e[2]); E[0]/=temp; E[1]/=temp; E[2]/=temp; // Laske vektori H, joka puolittaa vektorien E ja L välisen kulman. H[0]=L[0]+E[0]; H[1]=L[1]+E[1]; H[2]=L[2]+E[2]; temp=sqrt(h[0]*h[0]+h[1]*h[1]+h[2]*h[2]); H[0]/=temp; H[1]/=temp; H[2]/=temp; // Laske ympäristövalo + hajavalo + peiliheijastus I[0]= A*Cd[0] + Cd[0]*Cl[0]*pisteTulo(N, L) + G*Cl[0]*pow(pisteTulo(N, H), M); I[1]= A*Cd[1] + Cd[1]*Cl[1]*pisteTulo(N, L) + G*Cl[1]*pow(pisteTulo(N, H), M); I[2]= A*Cd[2] + Cd[2]*Cl[2]*pisteTulo(N, L) + G*Cl[2]*pow(pisteTulo(N, H), M); // Anna tulos OpenGL:lle. glcolor3f(i[0], I[1], I[2]); Tämä johtaa kuitenkin ongelmaan teksturoinnin yhteydessä. Pinnan värihän saadaan tällöin tekstuurista, joten se voi olla eri jokaisella pikselillä. Miten siis tekstuuri suhtautuu valaistukseen? Jos luit sarjan edellisen osan muistat varmaan, että värin ja tekstuurin yhdistämisestä huolehtii texture environment, joka oletuksena kertoo värin ja tekstuurin keskenään (GL_MODULATE). Jos jätemme valoyhtälöstä pois komponentin C d saamme yhtälön: I = 1/(k*d^2) * ( A + C l * ( N L ) + C l * G * ( N H ) ^ M + E ). Jos nyt laskemme valaistuksen tämän yhtälön mukaisesti ja annamme texture environmentin kertoa värin tektuurilla saamme lopulliseksi väriksi: I = C d * ( 1/(k*d^2) * ( A + C l * ( N L ) + C l * G * ( N H ) ^ M + E ) ), joka on muuten sama kuin alkuperäinen yhtälömmekin paitsi, että myös peiliheijastus tulee kerrottua pinnan värillä. Tämä ei ole suuri katastrofi, jos peiliheijastuksen arvo on mitättömän pieni ( G on noin 0 ), mutta
7 pilaa koko vaikutelman, jos peiliheijastuksen osuus on merkittävä. Tämän ongelman voi korjata toissijaisella värillä, josta puhumme seuraavaksi. 2.1 Toissijainen väri glcolor3f()-funktiolla annettua väriä kutsutaan ensisijaiseksi väriksi. On kuitenkin olemassa laajennus GL_EXT_secondary_color, joka sallii toissijaisen värin määrittämisen. Tämä laajennus tuo mukanaan mm. funktion glsecondarycolor3fext(glfloat red, Glfloat green, Glfloat blue), jolla toissijainen väri annetaan. Toissijainen väri ei osallistu texture environmenttiin, vaan se lisätään (siis lasketaan yhteen) pikselin väriin vasta sen jälkeen kun teksture environment on tehnyt tehtävänsä. Tämä kuitenkin tapahtuu vain, jos GL_ COLOR_SUM_EXT on päällä. Se saadaan päälle kutsulla glenable(gl_ COLOR_SUM_EXT). Korjataan nyt edellisen kappaleen funktiota niin, että se olettaa pinnan värin tulevan tekstuurista ja erottaa peiliheijastuksen toissijaiseen väriin. Funktio olettaa, että GL_EXT_secondary_color-laajennos on tuettu ja että GL_COLOR_SUM_EXT ja GL_TEXTURE_2D ovat päällä ja texture environment on GL_MODULATE-moodissa. void valo2(float Pv[3], float Pl[3], float Cl[3], float N[3]) const float A=0.1; const float G=0.9; const float M=16; float L[3], E[3], H[3], I[3], S[3]; float temp; // Laske vektori L, joka osoittaa kohti valoa. L[0]=Pl[0]-Pv[0]; L[1]=Pl[1]-Pv[1]; L[2]=Pl[2]-Pv[2]; temp=sqrt(l[0]*l[0]+l[1]*l[1]+l[2]*l[2]); L[0]/=temp; L[1]/=temp; L[2]/=temp; // Laske vektori E, joka osoittaa kohti kameraa. E[0]=-Pv[0]; E[1]=-Pv[1]; E[2]=-Pv[2]; temp=sqrt(e[0]*e[0]+e[1]*e[1]+e[2]*e[2]); E[0]/=temp;
8 E[1]/=temp; E[2]/=temp; // Laske vektori H, joka puolittaa vektorien E ja L välisen kulman. H[0]=L[0]+E[0]; H[1]=L[1]+E[1]; H[2]=L[2]+E[2]; temp=sqrt(h[0]*h[0]+h[1]*h[1]+h[2]*h[2]); H[0]/=temp; H[1]/=temp; H[2]/=temp; // Laske ympäristövalo + hajavalo I[0]= A + Cl[0]*pisteTulo(N, L); I[1]= A + Cl[1]*pisteTulo(N, L); I[2]= A + Cl[2]*pisteTulo(N, L); // Laske peiliheijastus S[0]= G*Cl[0]*pow(pisteTulo(N, H), M); S[1]= G*Cl[1]*pow(pisteTulo(N, H), M); S[2]= G*Cl[2]*pow(pisteTulo(N, H), M); // Anna tulos OpenGL:lle. glcolor3f(i[0], I[1], I[2]); glsecondarycolor3fext(s[0], S[1], S[2]); 3 OpenGL:n oma valojärjestelmä Ei kuitenkaan ole pakko kirjoittaa omaa funktiota, joka laskee valaistuksen, sillä OpenGL sisältää myös oman valaistusjärjestelmän. Valaistus saadaan päälle kutsulla glenable(gl_lighting);. Kun valaistus on päällä laskee OpenGL valot automaattisesti ja korvaa värit saamillaan tuloksilla. glcolor3f()-funktiolla ei siis ole mitään vaikutusta silloin kun valaistus on päällä! Valonlähteitä on maksimissaan kahdeksan ja niitä voidaan laittaa päälle ja pois yksitellen glenable() ja gldisable()-funktioilla, joille annetaan parametrina GL_LIGHTx, jos x on valon numero väliltä 0-7. Valon attribuutteja (sijaintia, väriä jne...) voidaan muuttaa gllightfv()-funktiolla, jonka prototyyppi näyttää tältä: void gllightfv(glenum light, GLenum pname, const GLfloat *params); Ensimmäinen parametri kertoo valon, jonka attribuutteja muutetaan (siis GL_LIGHTx). Toinen on muuttava attribuutti. Tärkeimmät ovat GL_AMBIENT (ympäristovalon eli
9 A:n arvo), GL_DIFFUSE ja GL_SPECULAR (valon väri eli Cl, OpenGL siis sallii eri valon värit hajavalolle ja peiliheijastukselle), GL_QUADRATIC_ATTENUATION (vaimenemisen vakio k) ja GL_POSITION (valon sijainti). Viimeinen parametri on osoitin 4-komponenttiseen taulukkoon, joka sisältää attribuutin uuden arvon. 3 ensimmäistä kenttää ovat attribuutin uusi arvo ja viimeisen kentän on oltava 1. Paitsi GL_QUADRATIC_ATTENUATION tapauksessa, jossa taulukko sisältää vain yhden arvon. Valaistavan pinnan ominaisuuksia voidaan asettaa glmaterialfv()-funktiolla. Prototyyppi näyttää tältä: void glmaterialfv(glenum face, GLenum pname, const GLfloat *params); Ensimmäisen parametrin on oltava GL_FRONT_AND_BACK. Toisen parametrin mahdolliset arvot ovat: GL_AMBIENT_AND_DIFFUSE (pinnan väri), GL_SPECULAR (pinnan kiiltävyys eli G:n arvo), GL_EMISSION (itsesäteillyn valon määrä eli E:n arvo) ja GL_SHININESS (vakion M arvo). Viimeinen parametri on jälleen kerran osoitin 4 komponenttiseen taulukkoon, joka sisältää uuden arvon. Paitsi GL_SHININESS tapauksessa, jossa taulukko sisältää vain yhden arvon. Koska pinnan normaalia tarvitaan valaistuksen laskemiseen täytyy se antaa OpenGL:lle. Tämä tehdään funktiolla glnormal3f(), jonka prototyyppi näyttää tältä: void glnormal3f(glfloat nx, GLfloat ny, GLfloat nz); Se siis ottaa normaalivektorin x, y ja z komponentit parametrinaan. Huomaa, että tämän vektorin pituuden tulee olla 1. Tätä funktiota kutsutaan glbegin() ja glend()-funktioiden välissä ja jokaiselle verteksille erikseen. On olemassa GL_EXT_separate_specular_color-laajennus, joka saa OpenGL erottamaan laskemansa valon peiliheijastuskomponentin toissijaiseksi väriksi. Tämä tehdään kutsulla
10 gllightmodel(gl_light_model_color_control_ext, GL_ SEPARATE_SPECULAR_COLOR_EXT);. GL_EXT_separate_specular_color saattaa olla tuettuna vaikka GL_EXT_secondary_color ei olisikaan. Oikealla ilman peiliheijastusta ja muissa sen kanssa, mutta keskellä GL_SEPARATE_SPECULAR_COLOR_EXT ei ole päällä kun taas vasemmalla se on. 4 Pikselin tarkka valaistus Huomattavaa on, että OpenGL:n sisäinen valojärjestelmä laskee valot vain vertekseille. Ei siis jokaiselle pikselille erikseen. Tämän jälkeen jokaiselle verteksille lasketut valoarvot (värit), interpoloidaan pikseleille. Kaikki näyttää ihan hyvältä niin kauan kuin polygonien koko on tarpeeksi pieni ja valon lähde kaukana niistä. Jos näin ei ole alkavat virheet näkyä. Parempi olisikin, jos voisimme laskea valoarvot jokaiselle pikselille erikseen jolloin tuloksena olisi huomattavasti realistisempi kuva. Vasemmalla kuvatun 8 kolmiosta koostuvan pinnan valaistus laskettu vertekseille (keskellä) ja pikseleille (oikealla). glcolor3f()-funktiolla ei kuitenkaan voi antaa väriä erikseen jokaiselle pikselille. Ainoastaan vertekseille. Seuraavassa kappaleessa esittelen pikselivarjostimiksi kutsutun tekniikan, jolla tämä ongelma saadaan pois päiväjärjestyksestä, mutta sitä ennen esittelen muutaman kiertotien.
11 Jos sekä valo että piirrettävä polygoni ovat staattisia eli ne eivät liiku voidaan valon vaikutus piirtää etukäteen tekstuuriin esim. jollakin kuvankäsittelyohjelmalla. Tällöin säästetään myös tehoa, kun mitään valaistukseen liittyvää ei tarvitse laskea ajon aikana. Tätä tekniikkaa kutsutaan termillä "lightmapping" ja sitä käyttävät mm. pelit Quake 2 ja 3 sekä half-life. Ajatus voidaan viedä vieläkin pidemmälle. Miksei valoefektejä lasketa tekstuureihin ajon aikana ja muuttuneita tekstuureja sitten ladata uudestaan näytönohjaimen muistiin glteximage2d()-funktiolla. Jos tekstuurit ovat tarpeeksi matalaresoluutioisia, tämä on ihan toimiva vaihtoehto. Jos tekstuurit kuitenkin ovat kovin korkearesoluutioisia kuluu tekstuurien päivittämiseen liikaa aikaa ja menetelmä ei toimi. Tämän tekniikan nimi on dynamic lightmapping. Mm. pelit Alien vs Predator 1 ja 2 käyttävät tätä tekniikkaa. Texture environment osaa laskea erilaisia funktioita jokaiselle pikselille, yhdistäen eri tekstuureja. On itse asiassa mahdollista laskea texture environment:in avulla valoyhtälöt jokaiselle pikselille. Tähän tarvitaan laajennukset GL_ARB_texture_env_combine, GL_ARB_texture_env_crossbar (tai GL_NV_texture_env_combine4) ja GL_ARB_texture_env_dot3 ja vähintään 4 teksturointiyksikköä. Lisäksi peiliheijastuksessa tarvittava potenssiinkorotus ei ole mahdollinen, joten sitä on arvioitava jollakin yksinkertaisemmalla funktiolla. 5 Verteksi- ja pikselivarjostinohjelmat Verteksi- tai pikselivarjostin on ohjelma tai pidemminkin funktio, jonka OpenGL suorittaa jokaista verteksiä/pikseliä kohden. Parasta tässä on, että voit kirjoittaa tämän funktion itse. Näitä funktioita kutsutaan varjostimiksi, koska niitä käytetään usein nimenomaan valaistuksen laskentaan. Varjostinohjelmat saavat syötteenään verteksin/pikselin kaikki arvot, kuten värin ja sijainnin ja tuottavat tuloksenaan uudet arvot. Huomaa, että koska pikselivarjostinohjelmat suoritetaan kerran jokaista pikseliä kohden, ja kuvassa voi helposti olla miljoonia pikseleitä kasvaa tarvittavan tehon määrä valtavaksi. Tämän takia pikselivarjostimet toimivat vain kaikkein uusimmissa näytönohjaimissa, kuten GeForceFX ja Ati Rodeon Nämä varjostimet ovat
12 saatavilla laajennusten GL_ARB_vertex_program, GL_ARB_fragment_program, GL_ARB_vertex_shader ja GL_ARB_fragment_shader muodossa. Verteksivarjostimet eivät tuo varsinaisesti mitään uutta. Ne saavat syötteenään verteksin sijainnin, värin jne. Suorittavat näillä jotain laskentaa ja korvaavat arvot uusilla. Olisit voinut tietenkin laskea nämä uudet arvot omassa ohjelmassasi ja antaa ne OpenGL:lle alkuarvoina, joilloin koko verteksivarjostinta ei olisi tarvittu. Etu on siinä, että verteksivarjostimen koodi suoritetaan näytönohjaimen prosessorilla, joka on nimenomaan erikoistunut grafiikan piirtämiseen ja suorittaa verteksivarjostinohjelman yleensä (joskaan ei aina) nopeammin kuin tietokoneen keskusyksikkö. Näin ollen verteksivarjostimet nostavat ohjelman suorituskykyä, ei sen graafista laatua. Pikselivarjostimet ovat sen sijaan toinen juttu. Ei nimittäin ole muuta keinoa tehdä pikselikohtaisia laskutoimituksia (texture environment:illa kikkailua lukuunottamatta). Niiden avulla on mahdollista laskea blinnin tai phongin valoyhtälöt jokaiselle pikselille erikseen. Mm. Doom 3:n hieno grafiikka perustuu tähän. Valitettavasti pikselivarjostimilla on katastrofaalinen vaikutus suorituskykyyn. Esim. 800x600 resoluutioisessa ikkunassa on pikseliä (olettaen että yhtään pikseliä ei piirretä kahdesti). Jos pikselivarjostin, jossa on vain 10 rivia koodia, suoritetaan jokaiselle pikselille tekee se lähes 5 miljoonaa suoritettavaa koodiriviä. On siinä näytönohjaimella laskemista. Varjostinohjelmat voidaan kirjoittaa, joko konekielellä (laajennukset GL_ARB_vertex_program ja GL_ARB_fragment_program) tai korkeamman tason glslang-kielellä (laajennukset GL_ARB_vertex_shader ja GL_ARB_fragment_shader) (myös Direct3D:llä on vastaavanlainen korkeamman tason kieli nimeltä HLSL). Lisäksi on olemassa NVidian kehittämä Cg. Se on siitä vekkuli, että se toimii sekä OpenGL:ssä, että Direct3D:ssä. Jotta voisit käyttää varjostinohjelmia sinun täytyy opetella jokin näistä kielistä. En kuitenkaan aijo esitellä niitä sen enempää, sillä niistä saisi vaikka oman artikkelinsa. Varjostinohjelmat ovat kuitenkin tulevaisuutta, joten niitä kannattaa joskus edes vilkaista.
13 6 Sapluunapuskuri Ennen kuin voimme mennä eteenpäin pitää minun esitellä sinulle yksi kätevä työkalu nimeltä sapluunapuskuri (englanniksi stencil buffer). Sapluunapuskuri toimii nimensä mukaan sapluunana. Ensin sapluunapuskuriin piirretään jotain, jonka jälkeen sapluunatestaus asetetaan päälle. Tämän jälkeen pikselit piirtyvät vain niihin kohtiin, joissa sapluunapuskuriin on piirretty jotain (tai halutessa toisin päin). Ennen kuin sapluunapuskuria voidaan käyttää pitää se laittaa päälle. Tämä tehdään kutsulla glenable(gl_stencil_test). Sapluunapuskuriin ei kuitenkaan voida tallentaa syvyysarvoja (kuten syvyyspuskuriin) tai väriarvoja kuten väripuskuriin, vaan lukuja väliltä (olettaen, että sapluunapuskurille varattujen bittien määrä per pikseli on 8). Se mitä sapluunapuskurissa olevalle luvulle tapahtuu sinne piirrettäessä valitaan glstencilop()-funktiolla. Prototyyppi näyttää tältä: void glstencilop(glenum fail, GLenum zfail, GLenum zpass); Kolme eri tapausta. Eli mitä tehdään kun pikseli ei läpäise sapluunatestiä (fail), mitä tehdään, kun pikseli läpäisi sapluunatestin, mutta ei syvyystestiä (zfail) ja mitä tehdään, kun pikseli läpäisi molemmat (zpass). Kaikkien parametrien mahdolliset arvot ovat: GL_KEEP (ei muutosta), GL_ZERO (korvataan nollalla), GL_REPLACE (korvataan jollakin vakioarvolla, joka annetaan myöhemmin esiteltävällä glstencilfunc() -funktion ref-parametrina), GL_INCR (kasvattaa lukua yhdellä), GL_DECR (vähentää lukua yhdellä) ja GL_INVERT (kääntää bitit). Käytettävä sapluunatesti voidaan valita funktiolla glstencilfunc(). Sen prototyyppi on tämän näköinen: void glstencilfunc(glenum func, GLint ref, GLuint mask);
14 Parametri func kertoo käytettävän funktion. Mahdollisia vaihtoehtoja ovat GL_NEVER (pikseliä ei koskaan piirretä), GL_ALWAYS (pikseli läpäisee testin aina, eli sapluunatesti on pois päältä), GL_EQUAL (pikseli piirretään vain jos sen kohdalla oleva arvo sapluunapuskurissa on sama kuin ref-parametrin arvo), GL_LESS ja GL_GREATER. Viimeinen parametri on maski. Sen arvo on yleensä ~0 eli binääriluku Ennen käyttöä sapluunapuskuri on tietenkin tyhjennettävä. Se tapahtuu kutsulla glclear(gl_stencil_buffer_bit). Lisäksi on huomattava, että kun kirjoitamme sapluunapuskuriin emme varmaan halua samalla piirtää mitään väripuskuriin. Tämä voidaan estää kutsulla glcolormask(0,0,0,0); ja äskeisen vaikutus saadaan kumottua kutsulla glcolormask(1,1,1,1);. 7 Varjot OpenGL ei sisällä valmista glenable(gl_shadows)-mekanismia, jolla varjot voisi loihtia helposti. Tämä sen takia, että piirtäessään yhtä polygonia OpenGL ei tiedä mitä kaikkea se tulee vielä piirtämään ennen kuin kuva on valmis. On kuitenkin paljon algoritmeja, joilla varjoja voi tehdä. Helpointa olisi tietenkin käyttää ns. feikkivarjoja eli piirtää kuvaan jotain mikä näyttää hieman varjolta esim. musta ympyrä kappaleen alle. Kun halutaan fysikaalisesti realistisia varjoja tarvitaan hieman enemmän työtä. Kaksi kuuluisinta varjoalgoritmia ovat "shadow map"-algoritmi ja stencil shadow volumes - algoritmi. Kumpikaan algoritmi ei perustu siihen, että ne piirtäisivät varjon, vaan pidemminkin piirtävät kaiken muun paitsi varjon, jolloin varjon kohdat jäävät mustiksi. Itse pidän enemmän "stencil shadow volumes"-algoritmista, jota käytämme myös esimerkkiohjelmassamme, mutta esittelen ensin hieman hankalamman "shadow map"- algoritmin perusidean ja jätän yksityiskohdat lukijan oman tutkisen varaan. 7.1 "Shadow map"-algoritmi "Shadow map"-algoritmin idea on seuraavanlainen. Renderoidaan kuva ensin valonlähteen näkökulmasta. Valonlähteen on siis oltava suunnattu, eikä "shadow map"- algoritmi toimi pistemäisille valonlähteille (yksi syy miksi en pidä siitä). Kopioidaan
15 tämän kuvan syvyyspuskuri tekstuuriin. Kutsukaamme tätä tekstuuria nimellä shadow map. Vasemmalla näkymä valonlähteen perspektiivistä katsottuna. Oikealla tämän kuvan syvyyspuskuri esitettynä niin, että vaaleat kohteet ovat lähellä ja tummat kaukana. Huomaa kuinka valo ei "näe" omia varjojaan. Teksturoidaan tällä tekstuurilla kaikki kappaleet valiten tekstuurikoordinaatit niin, että tekstuuri tulee projisoitua kappaleiden päälle valonlähteestä katsottuna. Tämän jälkeen renderoidaan kuva normaalisti samalla testaten jokaiselle pikselille, onko sen etäisyys valonlähteestä suurempi kuin sen kohdalla shadow map:issa oleva arvo. Jos on, pikseli on varjossa ja se voidaan jättää piirtämättä, muuten ei. Vasemmalla näkymä ilman varjoja. Keskellä näkymä teksturoituna "shadow map"-tekstuurilla, joka on projisoitu näkymän päälle. Oikealla näkymä, jossa sellaiset pikselit joiden etäisyys valosta on suurempi kuin arvo sen "shadow map"-tekstuurissa on jätetty piirtämättä (mustiksi). Itse kuvan renderointi valonlähteestä nähtynä ei ole hankalaa. Syvyyspuskurin kopiointi tekstuuriin taas voidaan tehdä glcopytexsubimage2d()-funktiolla. Sen prototyyppi näyttää tältä. void glcopytexsubimage2d( GLenum target, GLint level,
16 GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ); Ensimmäisen parametrin on oltava GL_TEX_IMAGE_2D ja toisen 0. Offset-parametrit kertovat kohdan tekstuurista, johon kuva kopioidaan (yleensä 0,0) ja x, y kohdan ruudulta, josta data kopioidaan (yleensä 0,0). Width ja height ovat kopioitavan alueen koko. Huomaa, että tektuurin, johon data tällä funktiolla kopioidaan pitää olla jo valmiiksi olemassa eli se on täytetty jollakin datalla käyttäen glteximage2d()-funktioita. Lisäksi tämän tekstuurin tulee olla ns. "depth texture", tai muuten glcopytexsubimage2d() kopioi väridatan eikä syvyysdataa.. Tämä uusi tekstuurimuoto tulee GL_ARB_depth_texture-laajennoksen mukana ja tekstuuri on tätä muotoa, kun glteximage2d()-funktion components-parametri asetetaan symboliin GL_DEPTH_TEXTURE_ARB. Tekstuurikoordinaattien laskeminen eli tekstuurin projisointi kappaleiden päälle on aika matemaattinen juttu, jonka jätän käsittelemättä. Mainittakoon kuitenkin, että OpenGL sisältää automaattisen tekstuurikoordinaattien generoinnin, jolla tämä voidaan hoitaa. Kun shadow map on luotu ja kappaleet teksturoitu sillä jää enää jäljelle kysymys: Kuinka oikein testaamme onko pikseli kauempana valosta kuin sen shadow map arvo? Voisimme tietenkin suorittaa tämän testin pikselivarjostimessa, mutta OpenGL sisältää ihan valmiin laajennuksen tätä varten. Tämän laajennuksen nimi on GL_ARB_shadow. Jätän tähän laajennukseen tutustumisen lukijan omalle vastuulle ja siirryn "stencil shadow volumes"- algoritmiin.
17 7.2 Stencil shadow volumes -algoritmi Shadow volume eli "katvetila" (jos tiedät paremman suomennoksen niin kerro toki minullekkin) on monitahokas, joka sulkee sisäänsä kaikki ne pisteet, jotka jäävät varjoon ja vastaavasti mikään katvetilan ulkopuolella oleva piste ei ole varjossa. Algoritmin idea on muodostaa monitahokkaalle valonlähteestä päin katsottu silhuetti. Venyttää tätä silhuettia valonlähteestä poispäin joilloin muodostuu monitahokkaan katvetila valonlähteen suhteen. Monitahokkaan silhuetin löytäminen saattaa aluksi tuntua hankalalta tehtävältä, mutta se on itse asiassa aika helppoa. Seuraavassa yksi algoritmi. Parempiakin varmasti löytyy, mutta uskon tämän olevan aika helppo ymmärtää. for (jokaiselle monitahokaan taholle) if (tämä taho osoittaa kohti valoa) for (jokaiselle tämän tahon vierustaholle) if (tämä vierustaho EI osoita kohti valoa) Tahojen välinen särmä kuuluu silhuettiin. Silhuetin on löytymisen jälkeen se täytyy venyttää katvetilaksi. Tämä on yksinkertaista. Projisoidaan jokaisesta särmästä kopio poispäin valonlähteestä ja yhdistetään tämä särmä alkuperäisen kanssa nelikulmioksi, joka muodostaa yhden katvetilan tahoista. Näin saadaan päistä avoin katvetila. Tämä katvetila voidaan vielä tarvittaessa sulkea käyttämällä alkuperäisen monitahokkaan omia polygoneja. Kun katvetila on muodostettu herää enää kysymys: Kuinka testataan mitkä pikselit ovat sen sisässä ja mitkä sen ulkopuolella? Kikka on seuraavanlainen. Ensin kuva renderöidään normaalisti, mutta tummemmalla värillä (esim. käyttäen pelkkää ympäristövaloa) täyttäen samalla syvyyspuskuri. Tämän jälkeen syvyyspuskurin päivitys laitetaan pois päältä ( gldepthmask(gl_false) ), mutta säilyttäen syvyystestaus päällä.
18 Tämän jälkeen katvetila piirretään sapluunapuskuriin ja saplaanaoperaatio asetetaan sellaiseksi, että sapluunapuskurin bitit, käännetään aina, kun sinne piirretään jotain ( glstencilop(gl_keep, GL_KEEP, GL_INVERT) ). Näin katvetilan sisään jäävät pikselit saadaan arvoon 1 ja sen ulkopuoliset arvoon 0. Tämä sen takia, että syvyystestauksesta johtuen katvetilan ulkopuoliset bitit käännetään parillinen määrä kertoja, kun taas sisällä olevat pariton määrä kertoja. Tämän jälkeen kuva piirretään uudestaan oikealla värillä, mutta tällä kertaa saplaanatestaus päällä niin, että piirto tapahtuu vain niihin kohtiin missä saplaanapuskurin arvo on 0 ( glstencilfunc(gl_equal, 0, ~0) ). Näin ollen varjostetulle alueelle ei piirry mitään ja niihin jää tumma varjon väri. Oikealla kaksi valaistua keilaa. Keskellä pystyssä olevan keilan katvetila havainnollistettu. Oikealla keilat on piirretty niin, että kaikki katvetilan sisään jäävät pikselit on jätetty piirtämättä (jäävät siis mustiksi). Valitettavasti koverien monitahokkaiden tapauksessa antamani algoritmi tuottaa silhuetteja, jotka leikkaavat itsensä. Tällöin bittien kääntäminen sapluunapuskurissa ei anna oikeaa tulosta (kuten käy myös silloin kun kamera on katvetilan sisässä). Bittien kääntämisen sijaan voidaan käyttää ns. Carmack s reverse -algoritmia, jossa katvetila piirretään kaksi kertaa. Ensimmäisellä kerralla sen etupuoli sapluunapuskurin arvoa kasvattaen ja toisella sen takapuoli sapluunapuskurin arvoa vähentäen, jolloin saadaan taas katvetilan ulkopuolella olevat bitit arvoon 0 ja muut johonkin nollasta poikkeavaan arvoon. Jätän kuitenkin tähän algoritmiin tutustumisen lukijan omalle vastuulle.
19 8 Esimerkkiohjelma Esimerkkiohjelma piirtää tason ja sen päälle kuution ja yhden valonlähteen. Sekä taso, että kuutio valaistaan OpenGL:n omilla valoilla ja varjot tehdään käyttäen stencil shadow volumes -algoritmia. Tämä on tähän astisista esimerkkiohjelmista monimutkaisin, mutta ei mahdoton ymmärtää. Voit imuroida oheisen lähdekoodin ja valmiiksi käännetyn version tästä: #include <windows.h> #include <gl\gl.h> #include <gl\glu.h> #include <math.h> //#include <gl\glext.h> // Ei tarvita tässä ohjelmassa // Määrittele laitekonteksti globaaliksi sitä nimittäin tarvitaan myös pääfunktiossa. HDC hdc; // Valon sijainti float lightpos[4]= 0, 5, 0, 1 ; // Viestinkäsittelijä LRESULT CALLBACK WindowProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) switch (umsg) // Koska piirrämme ikkunan sisällön pääsilmukassa jatkuvasti uudelleen // reakoimme WM_PAINT-viestiin vain tyhjentämällä ikkunan mustaksi. case WM_PAINT: PAINTSTRUCT p; BeginPaint(hwnd, &p); glclear(gl_color_buffer_bit); SwapBuffers(hdc); EndPaint(hwnd, &p); return 0; // Ikkuna yritetään sulkea kutsu PostQuitMessage()-funktiota. case WM_CLOSE: PostQuitMessage(0); return 0; // Käsittele myös WM_SIZE se lähetetään ikkunalle aina kun sen kokoa muutetaan. // Tämä on oiva tilaisuus muuttaa viewport // oikean kokoiseksi peittämään koko ikkuna. case WM_SIZE:
20 // Ikkunan uusi koko saadaan lparam parametrista LOWORD ja HIWORD makroilla. glviewport(0, 0, LOWORD(lParam), HIWORD(lParam)); return 0; // Viestiä ei käsitelty kutsu DefWindowProc()-funktiota. return DefWindowProc(hwnd, umsg, wparam, lparam); int luoikkuna(unsigned int leveys, unsigned int korkeus, char *otsikko) // Rekisteröi ikkunaluokka WNDCLASS wc; memset(&wc, 0, sizeof(wndclass)); wc.style = CS_HREDRAW CS_VREDRAW CS_OWNDC; wc.hcursor= LoadCursor(NULL, IDC_ARROW); wc.lpfnwndproc = (WNDPROC) WindowProc; wc.hinstance = GetModuleHandle(NULL); wc.lpszclassname = "OpenGLtutoriaali"; if (!RegisterClass(&wc)) return 0; // Luo ikkuna RECT r; r.left=getsystemmetrics(sm_cxscreen)/2-leveys/2; r.top=getsystemmetrics(sm_cyscreen)/2-korkeus/2; r.right=r.left+leveys; r.bottom=r.top+korkeus; AdjustWindowRectEx(&r, WS_CLIPSIBLINGS WS_CLIPCHILDREN WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW); HWND hwnd; hwnd=createwindowex(ws_ex_appwindow, "OpenGLtutoriaali", otsikko, WS_CLIPSIBLINGS WS_CLIPCHILDREN WS_OVERLAPPEDWINDOW, r.left, r.top, r.right-r.left, r.bottom-r.top, NULL, NULL, GetModuleHandle(NULL), NULL); // Luo laitekonteksti hdc=getdc(hwnd); if (!hdc) return 0; // Valitse pikseliformaatti PIXELFORMATDESCRIPTOR pfd; memset(&pfd, 0, sizeof(pixelformatdescriptor)); pfd.nsize=sizeof(pixelformatdescriptor); pfd.nversion=1; pfd.dwflags=pfd_draw_to_window PFD_SUPPORT_OPENGL PFD_DOUBLEBUFFER; pfd.ipixeltype=pfd_type_rgba; pfd.credbits=8; pfd.cgreenbits=8; pfd.cbluebits=8; pfd.calphabits=8;
21 pfd.cstencilbits=8; pfd.cdepthbits=16; pfd.ilayertype=pfd_main_plane; int pixelformat; pixelformat=choosepixelformat(hdc, &pfd); if (!pixelformat) return 0; if (!SetPixelFormat(hdc, pixelformat, &pfd)) return 0; // Luo renderöintikonteksti HGLRC hrc; hrc=wglcreatecontext(hdc); if (!hrc) return 0; if (!wglmakecurrent(hdc, hrc)) return 0; // Tuo ikkuna näkyviin ShowWindow(hwnd, SW_SHOW); SetForegroundWindow(hwnd); SetFocus(hwnd); // Palauta onnistuminen return 1; // Laskee kahden vektorin pistetulon float pistetulo(float v1[3], float v2[3]) return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]; // Taso piirretään käyttäen useita pieniä nelikulmioita // paremman valaistuksen saavuttamiseksi void piirrataso(void) int x, z; glbegin(gl_quads); glnormal3f(0,1,0); for (z=0; z<22; z+=2) for (x=0; x<22; x+=2) glvertex3f(-10+x, 0, -10+z); glvertex3f(-10+x, 0, -10+z+2); glvertex3f(-10+x+2, 0, -10+z+2); glvertex3f(-10+x+2, 0, -10+z); glend(); // Piirtää kuution tai sen katvetilan, jos katvetila-parametri on TRUE void piirrakuutio(bool katvetila) // Data piirrettävää kuutiota varten static float vertex[8][3]=-1,0,-1,1,0,-1,-1,2,-1,1,2,-1,
22 -1,0,1, 1,0, 1,-1,2, 1,1,2, 1; static int index[6][4]= 0,2,3,1, 4,5,7,6, 5,1,3,7, 4,6,2,0, 7,3,2,6, 4,0,1,5 ; // Tahojen normaalit static float normal[6][3]=0,0,-1,0,0,1,1,0,0,-1,0,0,0,1,0,0,-1,0; // Katvetilan muodostusta varten jokaisen tahon on tiedettävä naapurinsa. static int naapuri[6][4]=3,4,2,5,5,2,4,3,5,0,4,1, 1,4,0,5,2,0,3,1,3,0,2,1; // Jokaiselle verteksille valoa kohti osoittava vektori. static float L[8][3]; if (!katvetila) // Piirrä kuutio glbegin(gl_quads); int i, j; for (i=0; i<6; i++) glnormal3f(normal[i][0], normal[i][1], normal[i][2]); for (j=0; j<4; j++) glvertex3f(vertex[ index[i][j] ][0], vertex[ index[i][j] ][1], vertex[ index[i][j] ][2]); glend(); else int i,j; // Laske valoa kohti osoittavat vektorit. for (i=0; i<8; i++) L[i][0]=lightPos[0]-vertex[i][0]; L[i][1]=lightPos[1]-vertex[i][1]; L[i][2]=lightPos[2]-vertex[i][2]; // Piirrä katvetila. // Tässä tulee sairaan paljon indeksointia, joka olisi voitu välttää // jonkinlaisen verteksi-structuren ja osoittimien käytöllä. glbegin(gl_quads); // Jokaiselle taholle for (i=0; i<6; i++) // Jos tämä taho osoittaa kohti valoa if (pistetulo( normal[i], L[ index[i][0] ] )>=0) // Jokaiselle vierustaholle for (j=0; j<4; j++) // Jos tämä vierustaho EI osoita kohti valoa if (pistetulo(normal[ naapuri[i][j] ], L[ index[ naapuri[i][j] ][0] ])<0)
23 // Tahojen välinen särmä kuuluu silhuettiin // venytä se nelikulmioksi poispäin valosta. glvertex3f(vertex[ index[i][j] ][0], vertex[ index[i][j] ][1], vertex[ index[i][j] ][2]); glvertex3f(vertex[ index[i][(j+1)%4] ][0], vertex[ index[i][(j+1)%4] ][1], vertex[ index[i][(j+1)%4] ][2]); glvertex3f(vertex[ index[i][(j+1)%4] ][0]-100*L[ index[i][(j+1)%4] ][0], vertex[ index[i][(j+1)%4] ][1]-100*L[ index[i][(j+1)%4] ][1], vertex[ index[i][(j+1)%4] ][2]-100*L[ index[i][(j+1)%4] ][2]); glvertex3f(vertex[ index[i][j] ][0]-100*L[ index[i][j] ][0], vertex[ index[i][j] ][1]-100*L[ index[i][j] ][1], vertex[ index[i][j] ][2]-100*L[ index[i][j] ][2]); glend(); // Pääfunktio int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) float angle=0; // Luo ikkuna if (!luoikkuna(800, 600, "OpenGL:n perusteet - Osa 4: Valot ja varjot")) return 0; // Määrittele viewport koko ikkunan kokoiseksi glviewport(0, 0, 800, 600); // Koska koordinaatisto on itseasiassa matriisi täytyy meidän ottaa // projektiomatriisi käsiteltäväksi ennen gluperspective-kutsua. glmatrixmode(gl_projection); gluperspective(60, 800.0/600.0, 1, 100); // Kaikki matriisia muuttavat käskyt vaikuttavat tämän jälkeen modelview-matriisiin glmatrixmode(gl_modelview); // Laita näkymättömien pintojen poisto ja sysyyspuskurialgoritmi päälle. glenable(gl_cull_face); // Valitse syvyystestausfunktio "<=" oletuksena olevan "<" tilalle. gldepthfunc(gl_lequal); glenable(gl_depth_test); // Aseta valo nro. 0 päälle float Cl[4]=0.8,0.8,0.8,1; float A[4]=0.2,0.2,0.2,1; float Cd[4]=1,1,1,1; gllightfv(gl_light0, GL_DIFFUSE, Cl); // Väri gllightfv(gl_light0, GL_AMBIENT, A); // Ympätisrövalon määrä
24 glmaterialfv(gl_front_and_back, GL_AMBIENT_AND_DIFFUSE, Cd); // Pinnan väri glenable(gl_light0); // OpenGL lisää valaistukseen vielä yhden valonlähteistä // riippumattoman ympäristövalon, josta haluamme päästä eroon. float nolla[4]=0,0,0,1; gllightmodelfv(gl_light_model_ambient, nolla); // Viestinkäsittelysilmukka MSG msg; while(1) if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) if (msg.message==wm_quit) break; TranslateMessage(&msg); DispatchMessage(&msg); else // Tyhjennä väripuskuri, syvyyspuskuri ja sapluunapuskuri glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT GL_STENCIL_BUFFER_BIT); // Aseta modelview-matriisi glloadidentity(); // "Resetoi" matriisi yksikkömatriisiksi gltranslatef(0, -3, -10); // Siirrä hieman kauemmaksi kamerasta glrotatef(angle, 0, 1, 0); // Pyöritä hieman Y-akselin ympäri // Kasvata pyörityskulmaa hieman angle+=0.05; // Siirrä valoa lightpos[0]=5*sin(angle*-0.2); lightpos[1]=5+sin(angle*0.5); lightpos[2]=5*cos(angle*-0.2); gllightfv(gl_light0, GL_POSITION, lightpos); // Ensimmäinen vaihe. // täytetään syvyyspuskuri ja piirretään kuva käyttäen pelkkää ympäristövaloa gldisable(gl_lighting); gldisable(gl_stencil_test); glcolor3f(a[0], A[1], A[2]); piirrataso(); piirrakuutio(false); // Toinen vaihe // Piirrä katvetila sapluunapuskuriin // Jos haluat päästä eroon varjoista kommentoi tämä toinen vaihe pois gldisable(gl_cull_face); // Katvetilasta pitää piirtää kaikki osat glenable(gl_stencil_test); // Sapluunapuskuri päälle glcolormask(0, 0, 0, 0); // Emme halua päivittää väripuskuria gldepthmask(0); // Emmekä syvyyspuskuria glstencilfunc(gl_always, 0, 0); glstencilop(gl_keep, GL_KEEP, GL_INVERT); // Käännä bitit piirtäessä piirrakuutio(true);
25 glenable(gl_cull_face); glcolormask(1, 1, 1, 1); gldepthmask(1); // Viimeinen vaihe // Piirrä lopullinen kuva kohtiin, jossa sapluunapuskurin arvo on 0 glenable(gl_lighting); glstencilfunc(gl_equal, 0, ~0); glstencilop(gl_keep, GL_KEEP, GL_KEEP); piirrataso(); piirrakuutio(false); // Piirrä vielä valonlähde gldisable(gl_lighting); gldisable(gl_stencil_test); glpointsize(5); glbegin(gl_points); glcolor3f(1,1,0); glvertex3f(lightpos[0], lightpos[1], lightpos[2]); glend(); // Vaihda puskuri näytölle. SwapBuffers(hdc); return 0; 9 Loppusanat Tässä artikkelissa opit valoista ja varjoista. Tässä artikkelisarjassa olemme nyt käyneet läpi pintapuolisesti kaikki 3d grafiiikan perusasiat. Lopuksi listaan vielä joitakin linkkejä, joista löydät rutkasti lisää luottevaa OpenGL:stä ja 3D grafiikasta yleensäkkin. keskustelufoorumit löytyvät täältä. OpenGL:n virallinen kotisivu. Uutisia, viralliset speksit ja NeHe Productions. Netin ylivoimaisesti suosituimmat opengl tutoriaalit. - The Red Book. Virallinen OpenGL:n opaskirja. Tämä netistä löytyvä ilmaisversio on aika hemmetin vanha, mutta ajaa asiansa. Uusin versio on saatavilla vain kirjakaupoista.
26 - SGI:n ylläpitämä OpenGL:n laajennusrekisteri. Sama löytyy myös kaikkien näytönohjainvalmistajien kotisivuilta. - OpenGL Hardware Registry. Rekisteri, jossa on lueteltu valtavasti näytönohjaimia ja kerrottu mitä laajennuksia ne tukevat. - Mesa 3D Graphics Library. Software OpenGL "ajurit". Voit kokeilla näiden "ajurien" avulla laajennuksia, joita oma näytönohjaimesi ei tue. - OpenGL faq. Usein kysytyt kysymykset OpenGL:stä. - Game tutorials. 50 aloittelijoille tarkoitettua OpenGL-tutoriaalia. - Ultima game programming. Lähes 100 hieman edistyneimmille tarkoitettua OpenGLtutoriaalia. Raportoithan kaikki tästä artikkelista löytämäsi virheet (niin kirjoitus-, kuin asiavirheetkin) osoitteeseen markus.ilmola@pp.inet.fi, niin korjaan ne mahdollisimman nopeasti. Myös kaikki kommentit ja kysymykset ovat tervetulleita
OpenGL:n perusteet - Osa 2: 3D grafiikka
OpenGL:n perusteet - Osa 2: 3D grafiikka OpenGL on käyttöjärjestelmäriippumaton kirjasto 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen. Esimerkeissä
LisätiedotOpenGL:n perusteet - Osa 1: Ikkunan luominen
OpenGL:n perusteet - Osa 1: Ikkunan luominen OpenGL on käyttöjärjestelmäriippumaton kirjasto 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen.
LisätiedotOpenGL:n perusteet Osa 3: Teksturointi
OpenGL:n perusteet Osa 3: Teksturointi OpenGL on käyttöjärjestelmäriippumaton kirjasto 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen. Esimerkeissä
LisätiedotWindowsin sanomanvälitys. Juha Järvensivu 2007
Windowsin sanomanvälitys Juha Järvensivu juha.jarvensivu@tut.fi 2007 Sisällys Windowsin sanomat Sanomanvälitysmekanismi Ikkunan kahva Sanomien lähettäminen Esimerkki winamp Tapahtumapohjainen toiminta
LisätiedotSisällys. T-111.4300 Tietokonegrafiikan perusteet. OpenGL-ohjelmointi 11/2007. Mikä on OpenGL?
T-111.4300 Tietokonegrafiikan perusteet OpenGL-ohjelmointi 11/2007 Sisällys Mikä on OpenGL? historia nykytilanne OpenGL:n toiminta Piirtäminen ja matriisit Muuta hyödyllistä kameran sijoittaminen valaistus
LisätiedotTampereen yliopisto Tietokonegrafiikka 2013 Tietojenkäsittelytiede Harjoitus
Tampereen yliopisto Tietokonegrafiikka 201 Tietojenkäsittelytiede Harjoitus 6 1..201 1. Tarkastellaan Gouraudin sävytysmallia. Olkoon annettuna kolmio ABC, missä A = (0,0,0), B = (2,0,0) ja C = (1,2,0)
LisätiedotLuento 10: Näkyvyystarkastelut ja varjot. Sisältö
Tietokonegrafiikka / perusteet T-111.300/301 4 ov / 2 ov Luento 10: Näkyvyystarkastelut ja varjot Marko Myllymaa / Lauri Savioja 10/04 Näkyvyystarkastelut ja varjot / 1 Näkyvyystarkastelu Solurenderöinti
LisätiedotT Tietokonegrafiikan perusteet. OpenGL-ohjelmointi
T-111.4300 Tietokonegrafiikan perusteet OpenGL-ohjelmointi Id Softwaren huhtikuussa 2004 julkaisema Doom 3 -peli käyttää OpenGL-kirjastoa. Sisällys Mikä on OpenGL? historia nykytilanne OpenGL:n toiminta
LisätiedotLuku 6: Grafiikka. 2D-grafiikka 3D-liukuhihna Epäsuora valaistus Laskostuminen Mobiililaitteet Sisätilat Ulkotilat
2D-grafiikka 3D-liukuhihna Epäsuora valaistus Laskostuminen Mobiililaitteet Sisätilat Ulkotilat 2D-piirto 2-ulotteisen grafiikan piirto perustuu yleensä valmiiden kuvien kopioimiseen näyttömuistiin (blitting)
Lisätiedot3.3 Paraabeli toisen asteen polynomifunktion kuvaajana. Toisen asteen epäyhtälö
3.3 Paraabeli toisen asteen polynomifunktion kuvaajana. Toisen asteen epäyhtälö Yhtälön (tai funktion) y = a + b + c, missä a 0, kuvaaja ei ole suora, mutta ei ole yhtälökään ensimmäistä astetta. Funktioiden
LisätiedotPeilaus pisteen ja suoran suhteen Pythonin Turtle moduulilla
Peilaus pisteen ja suoran suhteen Pythonin Turtle moduulilla ALKUHARJOITUS Kynän ja paperin avulla peilaaminen koordinaatistossa a) Peilaa pisteen (0,0) suhteen koordinaatistossa sijaitseva - neliö, jonka
LisätiedotWindowsin sanomanvälitys. Juha Järvensivu juha.jarvensivu@tut.fi 2008
Windowsin sanomanvälitys Juha Järvensivu juha.jarvensivu@tut.fi 2008 Sisällys Windowsin sanomat ja Sanomanvälitysmekanismi Ikkunan kahva ja Sanomien lähettäminen Windows API ohjelmointi Resurssit Sanomat
LisätiedotPERUSLASKUJA. Kirjoita muuten sama, mutta ota välilyönti 4:n jälkeen 3/4 +5^2
PERUSLASKUJA Matemaattisten lausekkeiden syöttäminen: Kirjoita ilman välilyöntejä /+^2 Kirjoita muuten sama, mutta ota välilyönti :n jälkeen / +^2 Kopioi molemmat matematiikka-alueet ja liiku alueen sisällä
LisätiedotLuento 3: 3D katselu. Sisältö
Tietokonegrafiikan perusteet T-.43 3 op Luento 3: 3D katselu Lauri Savioja Janne Kontkanen /27 3D katselu / Sisältö Kertaus: koordinaattimuunnokset ja homogeeniset koordinaatit Näkymänmuodostus Kameran
LisätiedotLuku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti
Luku 6 Dynaaminen ohjelmointi Dynaamisessa ohjelmoinnissa on ideana jakaa ongelman ratkaisu pienempiin osaongelmiin, jotka voidaan ratkaista toisistaan riippumattomasti. Jokaisen osaongelman ratkaisu tallennetaan
LisätiedotBM20A5800 Funktiot, lineaarialgebra ja vektorit Harjoitus 4, Syksy 2016
BM20A5800 Funktiot, lineaarialgebra ja vektorit Harjoitus 4, Syksy 2016 1. Hahmottele karkeasti funktion f : R R 2 piirtämällä sen arvoja muutamilla eri muuttujan arvoilla kaksiulotteiseen koordinaatistoon
LisätiedotEsimerkkejä. OpenGL ohjelma. OpenGL tilakone. Geometriset primitiivit. Hyvät ja huonot polygonit. OpenGL Pipeline. Rasterointi
Tietokonegrafiikka / perusteet Ako/T-111.300/301 4 ov / 2 ov OpenGL 1 Yleistä harjoituksista OpenGL:n toiminta Primitiivit Kuvapuskurit Koordinaatistot ja projisointi Transformaatiot ja matriisit Valaistus
LisätiedotKerta 2. Kerta 2 Kerta 3 Kerta 4 Kerta 5. 1. Toteuta Pythonilla seuraava ohjelma:
Kerta 2 Kerta 3 Kerta 4 Kerta 5 Kerta 2 1. Toteuta Pythonilla seuraava ohjelma: 2. Tulosta Pythonilla seuraavat luvut allekkain a. 0 10 (eli, näyttää tältä: 0 1 2 3 4 5 6 7 8 9 10 b. 0 100 c. 50 100 3.
LisätiedotLuento 6: Piilopinnat ja Näkyvyys
Tietokonegrafiikan perusteet T-111.4300 3 op Luento 6: Piilopinnat ja Näkyvyys Janne Kontkanen Geometrinen mallinnus / 1 Johdanto Piilopintojen poisto-ongelma Syntyy kuvattaessa 3-ulotteista maailmaa 2-ulotteisella
LisätiedotDemokoodaus Linuxilla, tapaus Eternity
Demokoodaus Linuxilla, tapaus Eternity Tuomo Sipola tuomo.sipola@iki.fi Linkin lanit 9.4.2010 Tuomo Sipola tuomo.sipola@iki.fi () Demokoodaus Linuxilla, tapaus Eternity Linkin lanit 9.4.2010 1 / 17 Sisältö
LisätiedotPERUSLASKUJA. Kirjoita muuten sama, mutta ota KAKSI välilyöntiä (SEURAA ALUEMERKINTÄÄ) 4:n jälkeen 3/4 +5^2
PERUSLASKUJA Matemaattisten lausekkeiden syöttäminen: Kirjoita ilman välilyöntejä 3/4+^2 3 4+ 2 Kirjoita muuten sama, mutta ota KAKSI välilyöntiä (SEURAA ALUEMERKINTÄÄ) 4:n jälkeen 3/4 +^2 3 + 4 2 Kopioi
Lisätiedot9. Vektorit. 9.1 Skalaarit ja vektorit. 9.2 Vektorit tasossa
9. Vektorit 9.1 Skalaarit ja vektorit Skalaari on koon tai määrän mitta. Tyypillinen esimerkki skalaarista on massa. Lukumäärä on toinen hyvä esimerkki skalaarista. Vektorilla on taas suuruus ja suunta.
LisätiedotPong-peli, vaihe Koordinaatistosta. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 2/7. Tämän vaiheen aikana
Muilla kielillä: English Suomi Pong-peli, vaihe 2 Tämä on Pong-pelin tutoriaalin osa 2/7. Tämän vaiheen aikana Laitetaan pallo liikkeelle Tehdään kentälle reunat Vaihdetaan kentän taustaväri Zoomataan
LisätiedotVisualisoinnin perusteet
1 / 12 Digitaalisen arkkitehtuurin yksikkö Aalto-yliopisto Visualisoinnin perusteet Mitä on renderöinti? 2 / 12 3D-mallista voidaan generoida näkymiä tietokoneen avulla. Yleensä perspektiivikuva Valon
Lisätiedot815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset
815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 3 vastaukset Harjoituksen aiheena ovat imperatiivisten kielten muuttujiin liittyvät kysymykset. Tehtävä 1. Määritä muuttujien max_num, lista,
Lisätiedot10.2. Säteenjäljitys ja radiositeettialgoritmi. Säteenjäljitys
10.2. Säteenjäljitys ja radiositeettialgoritmi Säteenjäljitys Säteenjäljityksessä (T. Whitted 1980) valonsäteiden kulkema reitti etsitään käänteisessä järjestyksessä katsojan silmästä takaisin kuvaan valolähteeseen
Lisätiedot= 2 L L. f (x)dx. coshx dx = 1 L. sinhx nπ. sin. sin L + 2 L. a n. L 2 + n 2 cos. tehdään approksimoinnissa virhe, jota voidaan arvioida integraalin
BMA7 - Integraalimuunnokset Harjoitus 9. Määritä -jaksollisen funktion f x = coshx, < x < Fourier-sarja. Funktion on parillinen, joten b n = kun n =,,3,... Parillisuudesta johtuen kertoimet a ja a n saadaan
LisätiedotLuku 8. Aluekyselyt. 8.1 Summataulukko
Luku 8 Aluekyselyt Aluekysely on tiettyä taulukon väliä koskeva kysely. Tyypillisiä aluekyselyitä ovat, mikä on taulukon välin lukujen summa tai pienin luku välillä. Esimerkiksi seuraavassa taulukossa
LisätiedotMS-A0003/A0005 Matriisilaskenta Malliratkaisut 5 / vko 48
MS-A3/A5 Matriisilaskenta Malliratkaisut 5 / vko 48 Tehtävä (L): a) Onko 4 3 sitä vastaava ominaisarvo? b) Onko λ = 3 matriisin matriisin 2 2 3 2 3 7 9 4 5 2 4 4 ominaisvektori? Jos on, mikä on ominaisarvo?
LisätiedotTietotekniikan valintakoe
Jyväskylän yliopisto Tietotekniikan laitos Tietotekniikan valintakoe 2..22 Vastaa kahteen seuraavista kolmesta tehtävästä. Kukin tehtävä arvostellaan kokonaislukuasteikolla - 25. Jos vastaat useampaan
LisätiedotMatematiikan tukikurssi
Matematiikan tukikurssi Kurssikerta 9 1 Implisiittinen derivointi Tarkastellaan nyt yhtälöä F(x, y) = c, jossa x ja y ovat muuttujia ja c on vakio Esimerkki tällaisesta yhtälöstä on x 2 y 5 + 5xy = 14
Lisätiedot811312A Tietorakenteet ja algoritmit , Harjoitus 2 ratkaisu
811312A Tietorakenteet ja algoritmit 2017-2018, Harjoitus 2 ratkaisu Harjoituksen aiheena on algoritmien oikeellisuus. Tehtävä 2.1 Kahvipurkkiongelma. Kahvipurkissa P on valkoisia ja mustia kahvipapuja,
LisätiedotLuento 4: Näkyvyystarkastelut ja varjot
Tietokonegrafiikan jatkokurssi T-111.5300 4 op Luento 4: Näkyvyystarkastelut ja varjot Lauri Savioja 02/07 Näkyvyystarkastelut ja varjot / 1 Näkyvyystarkastelu Solurenderöinti Portaalirenderöinti Quad-/Octtree
Lisätiedot766320A SOVELTAVA SÄHKÖMAGNETIIKKA, ohjeita tenttiin ja muutamia teoriavinkkejä sekä pari esimerkkilaskua
7663A OVLTAVA ÄHKÖMAGNTIIKKA, ohjeita tenttiin ja muutamia teoriavinkkejä sekä pari esimerkkilaskua 1. Lue tenttitehtävä huolellisesti. Tehtävä saattaa näyttää tutulta, mutta siinä saatetaan kysyä eri
LisätiedotMatematiikan tukikurssi, kurssikerta 3
Matematiikan tukikurssi, kurssikerta 3 1 Epäyhtälöitä Aivan aluksi lienee syytä esittää luvun itseisarvon määritelmä: { x kun x 0 x = x kun x < 0 Siispä esimerkiksi 10 = 10 ja 10 = 10. Seuraavaksi listaus
Lisätiedot12. Javan toistorakenteet 12.1
12. Javan toistorakenteet 12.1 Sisällys Yleistä toistorakenteista. Laskurimuuttujat. While-, do-while- ja for-lauseet. Laskuri- ja lippumuuttujat. Tyypillisiä ohjelmointivirheitä. Silmukan rajat asetettu
LisätiedotOsoitin ja viittaus C++:ssa
Osoitin ja viittaus C++:ssa Osoitin yksinkertaiseen tietotyyppiin Osoitin on muuttuja, joka sisältää jonkin toisen samantyyppisen muuttujan osoitteen. Ohessa on esimerkkiohjelma, jossa määritellään kokonaislukumuuttuja
Lisätiedot(1) refleksiivinen, (2) symmetrinen ja (3) transitiivinen.
Matematiikassa ja muuallakin joudutaan usein tekemisiin sellaisten relaatioiden kanssa, joiden lakina on tietyn ominaisuuden samuus. Tietyn ominaisuuden samuus -relaatio on ekvivalenssi; se on (1) refleksiivinen,
LisätiedotVektorien pistetulo on aina reaaliluku. Esimerkiksi vektorien v = (3, 2, 0) ja w = (1, 2, 3) pistetulo on
13 Pistetulo Avaruuksissa R 2 ja R 3 on totuttu puhumaan vektorien pituuksista ja vektoreiden välisistä kulmista. Kuten tavallista, näiden käsitteiden yleistäminen korkeampiulotteisiin avaruuksiin ei onnistu
LisätiedotMatematiikassa ja muuallakin joudutaan usein tekemisiin sellaisten relaatioiden kanssa, joiden lakina on tietyn ominaisuuden samuus.
Matematiikassa ja muuallakin joudutaan usein tekemisiin sellaisten relaatioiden kanssa, joiden lakina on tietyn ominaisuuden samuus. Matematiikassa ja muuallakin joudutaan usein tekemisiin sellaisten relaatioiden
LisätiedotMatriisit ovat matlabin perustietotyyppejä. Yksinkertaisimmillaan voimme esitellä ja tallentaa 1x1 vektorin seuraavasti: >> a = 9.81 a = 9.
Python linkit: Python tutoriaali: http://docs.python.org/2/tutorial/ Numpy&Scipy ohjeet: http://docs.scipy.org/doc/ Matlabin alkeet (Pääasiassa Deni Seitzin tekstiä) Matriisit ovat matlabin perustietotyyppejä.
LisätiedotExcel syventävät harjoitukset 31.8.2015
Yleistä Excel on taulukkolaskentaohjelma. Tämä tarkoittaa sitä että sillä voi laskea laajoja, paljon laskentatehoa vaativia asioita, esimerkiksi fysiikan laboratoriotöiden koetuloksia. Excel-ohjelmalla
LisätiedotHarjoitus 7. 1. Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:
Harjoitus 7 1. Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti: class Lintu //Kentät private int _siivenpituus; protected double _aivojenkoko; private bool _osaakolentaa; //Ominaisuudet public int
LisätiedotTietorakenteet ja algoritmit
Tietorakenteet ja algoritmit Rekursio Rekursion käyttötapauksia Rekursio määritelmissä Rekursio ongelmanratkaisussa ja ohjelmointitekniikkana Esimerkkejä taulukolla Esimerkkejä linkatulla listalla Hanoin
LisätiedotMatematiikan tukikurssi
Matematiikan tukikurssi Kurssikerta 8 1 Suunnattu derivaatta Aluksi tarkastelemme vektoreita, koska ymmärrys vektoreista helpottaa alla olevien asioiden omaksumista. Kun liikutaan tasossa eli avaruudessa
LisätiedotAlgoritmit 1. Demot Timo Männikkö
Algoritmit 1 Demot 1 31.1.-1.2.2018 Timo Männikkö Tehtävä 1 (a) Algoritmi, joka tutkii onko kokonaisluku tasan jaollinen jollain toisella kokonaisluvulla siten, että ei käytetä lainkaan jakolaskuja Jaettava
Lisätiedot2.3 Voiman jakaminen komponentteihin
Seuraavissa kappaleissa tarvitaan aina silloin tällöin taitoa jakaa voima komponentteihin sekä myös taitoa suorittaa sille vastakkainen operaatio eli voimien resultantin eli kokonaisvoiman laskeminen.
LisätiedotA ja B pelaavat sarjan pelejä. Sarjan voittaja on se, joka ensin voittaa n peliä.
Esimerkki otteluvoiton todennäköisyys A ja B pelaavat sarjan pelejä. Sarjan voittaja on se, joka ensin voittaa n peliä. Yksittäisessä pelissä A voittaa todennäköisyydellä p ja B todennäköisyydellä q =
LisätiedotOhjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan.
Osoittimet Ohjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan. Muistilohkon koko riippuu muuttujan tyypistä, eli kuinka suuria arvoja muuttujan
LisätiedotLiite 1. Laajennettu Eukleideen algoritmi suoraviivainen tapa
Liite 1. Laajennettu Eukleideen algoritmi suoraviivainen tapa - johdanto - matemaattinen induktiotodistus - matriisien kertolaskun käyttömahdollisuus - käsinlaskuesimerkkejä - kaikki välivaiheet esittävä
LisätiedotReaalifunktioista 1 / 17. Reaalifunktioista
säilyy 1 / 17 säilyy Jos A, B R, niin funktiota f : A B sanotaan (yhden muuttujan) reaalifunktioksi. Tällöin karteesinen tulo A B on (aiempia esimerkkejä luonnollisemmalla tavalla) xy-tason osajoukko,
LisätiedotMatikkaa KA1-kurssilaisille, osa 3: suoran piirtäminen koordinaatistoon
Matikkaa KA1-kurssilaisille, osa 3: suoran piirtäminen koordinaatistoon KA1-kurssi on ehkä mahdollista läpäistä, vaikkei osaisikaan piirtää suoraa yhtälön perusteella. Mutta muut kansiksen kurssit, no
LisätiedotTIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli
TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op Assembly ja konekieli Tietokoneen ja ohjelmiston rakenne Loogisilla piireillä ja komponenteilla rakennetaan prosessori ja muistit Prosessorin rakenne
Lisätiedot1 Funktiot, suurin (max), pienin (min) ja keskiarvo
1 Funktiot, suurin (max), pienin (min) ja keskiarvo 1. Avaa uusi työkirja 2. Tallenna työkirja nimellä perusfunktiot. 3. Kirjoita seuraava taulukko 4. Muista taulukon kirjoitusjärjestys - Ensin kirjoitetaan
LisätiedotÖljysäiliö maan alla
Kaigasniemen koulu Öljysäiliö maan alla Yläkoulun ketaava ja syventävä matematiikan tehtävä Vesa Maanselkä 009 Ostat talon jossa on öljylämmitys. Takapihalle on kaivettu maahan sylintein muotoinen öljysäiliö
LisätiedotTutoriaaliläsnäoloista
Tutoriaaliläsnäoloista Tutoriaaliläsnäolokierroksella voi nyt täyttää anomuksen läsnäolon merkitsemisestä Esim. tagi ei toiminut, korvavaltimon leikkaus, yms. Hyväksyn näitä omaa harkintaa käyttäen Tarkoitus
LisätiedotOhjelmointiharjoituksia Arduino-ympäristössä
Ohjelmointiharjoituksia Arduino-ympäristössä Yleistä Arduino-sovelluksen rakenne Syntaksi ja käytännöt Esimerkki ohjelman rakenteesta Muuttujat ja tietotyypit Tietotyypit Esimerkkejä tietotyypeistä Ehtolauseet
LisätiedotTilanhallintatekniikat
Tilanhallintatekniikat 3D grafiikkamoottoreissa Moottori on projektin osa joka vastaa tiettyjen toiminnallisuuksien hallinnasta hallitsee kaikki vastuualueen datat suorittaa kaikki tehtäväalueen toiminnot
Lisätiedot12. Javan toistorakenteet 12.1
12. Javan toistorakenteet 12.1 Sisällys Yleistä toistorakenteista. Laskurimuuttujat. While-, do-while- ja for-lauseet. Laskuri- ja lippumuuttujat. Tyypillisiä ohjelmointivirheitä. Silmukan rajat asetettu
LisätiedotOhjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CSE-A1111 30.9.2015 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 1 / 27 Mahdollisuus antaa luentopalautetta Goblinissa vasemmassa reunassa olevassa valikossa on valinta Luentopalaute.
LisätiedotMAB3 - Harjoitustehtävien ratkaisut:
MAB - Harjoitustehtävien ratkaisut: Funktio. Piirretään koordinaatistoakselit ja sijoitetaan pisteet:. a) Funktioiden nollakohdat löydetään etsimällä kuvaajien ja - akselin leikkauspisteitä. Funktiolla
LisätiedotOhjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 3.2.2010 T-106.1208 Ohjelmoinnin perusteet Y 3.2.2010 1 / 36 Esimerkki: asunnon välityspalkkio Kirjoitetaan ohjelma, joka laskee kiinteistönvälittäjän asunnon
LisätiedotMatematiikan tukikurssi
Matematiikan tukikurssi Kurssikerta 4 Jatkuvuus Jatkuvan funktion määritelmä Tarkastellaan funktiota f x) jossakin tietyssä pisteessä x 0. Tämä funktio on tässä pisteessä joko jatkuva tai epäjatkuva. Jatkuvuuden
LisätiedotToinen harjoitustyö. ASCII-grafiikkaa
Toinen harjoitustyö ASCII-grafiikkaa Yleistä Tehtävä: tee Javalla ASCII-merkkeinä esitettyä grafiikkaa käsittelevä ASCIIArt-ohjelma omia operaatioita ja taulukoita käyttäen. Työ tehdään pääosin itse. Ideoita
LisätiedotHarjoitustyö: virtuaalikone
Harjoitustyö: virtuaalikone Toteuta alla kuvattu virtuaalikone yksinkertaiselle olio-orientoituneelle skriptauskielelle. Paketissa on testaamista varten mukana kaksi lyhyttä ohjelmaa. Ohjeita Noudata ohjelman
LisätiedotOhjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 2.2.2011 T-106.1208 Ohjelmoinnin perusteet Y 2.2.2011 1 / 37 Kännykkäpalautetteen antajia kaivataan edelleen! Ilmoittaudu mukaan lähettämällä ilmainen tekstiviesti
LisätiedotPRELIMINÄÄRIKOE PITKÄ MATEMATIIKKA 9.2.2011
PRELIMINÄÄRIKOE PITKÄ MATEMATIIKKA 9..0 Kokeessa saa vastata enintään kymmeneen tehtävään.. Sievennä a) 9 x x 6x + 9, b) 5 9 009 a a, c) log 7 + lne 7. Muovailuvahasta tehty säännöllinen tetraedri muovataan
LisätiedotAlgoritmit 1. Demot Timo Männikkö
Algoritmit 1 Demot 1 25.-26.1.2017 Timo Männikkö Tehtävä 1 (a) Algoritmi, joka laskee kahden kokonaisluvun välisen jakojäännöksen käyttämättä lainkaan jakolaskuja Jaettava m, jakaja n Vähennetään luku
LisätiedotMonipuolinen esimerkki
Monipuolinen esimerkki Lopuksi monipuolinen esimerkki, jossa ohjelmisto koostuu pääohjelmasta ja kahdesta aliohjelmasta, joista toinen on proseduuri ja toinen funktio. Funktio Sqrt(int n): int Sqrt(int
LisätiedotMATEMATIIKKA. Matematiikkaa pintakäsittelijöille. Ongelmanratkaisu. Isto Jokinen 2017
MATEMATIIKKA Matematiikkaa pintakäsittelijöille Ongelmanratkaisu Isto Jokinen 2017 SISÄLTÖ 1. Matemaattisten ongelmien ratkaisu laskukaavoilla 2. Tekijäyhtälöt 3. Laskukaavojen yhdistäminen 4. Yhtälöiden
LisätiedotRekursiolause. Laskennan teorian opintopiiri. Sebastian Björkqvist. 23. helmikuuta Tiivistelmä
Rekursiolause Laskennan teorian opintopiiri Sebastian Björkqvist 23. helmikuuta 2014 Tiivistelmä Työssä käydään läpi itsereplikoituvien ohjelmien toimintaa sekä esitetään ja todistetaan rekursiolause,
LisätiedotSisältö. 2. Taulukot. Yleistä. Yleistä
Sisältö 2. Taulukot Yleistä. Esittely ja luominen. Alkioiden käsittely. Kaksiulotteinen taulukko. Taulukko operaation parametrina. Taulukko ja HelloWorld-ohjelma. Taulukko paluuarvona. 2.1 2.2 Yleistä
LisätiedotITKP102 Ohjelmointi 1 (6 op)
ITKP102 Ohjelmointi 1 (6 op) Tentaattori: Antti-Jussi Lakanen 7. huhtikuuta 2017 Vastaa kaikkiin tehtäviin. Tee jokainen tehtävä erilliselle konseptiarkille. Kirjoittamasi luokat, funktiot ja aliohjelmat
LisätiedotAvaruuden kolme sellaista pistettä, jotka eivät sijaitse samalla suoralla, määräävät
11 Taso Avaruuden kolme sellaista pistettä, jotka eivät sijaitse samalla suoralla, määräävät tason. Olkoot nämä pisteet P, B ja C. Merkitään vaikkapa P B r ja PC s. Tällöin voidaan sanoa, että vektorit
Lisätiedot58131 Tietorakenteet ja algoritmit (kevät 2014) Uusinta- ja erilliskoe, , vastauksia
58131 Tietorakenteet ja algoritmit (kevät 2014) Uusinta- ja erilliskoe, 10..2014, vastauksia 1. [9 pistettä] (a) Todistetaan 2n 2 + n + 5 = O(n 2 ): Kun n 1 on 2n 2 + n + 5 2n 2 + n 2 +5n 2 = 8n 2. Eli
LisätiedotMatematiikan tukikurssi
Matematiikan tukikurssi Kurssikerta 4 Supremum ja inmum Tarkastellaan aluksi avointa väliä, Tämä on joukko, johon kuuluvat kaikki reaaliluvut miinus yhdestä yhteen Kuitenkaan päätepisteet eli luvut ja
Lisätiedot58131 Tietorakenteet ja algoritmit (kevät 2016) Ensimmäinen välikoe, malliratkaisut
58131 Tietorakenteet ja algoritmit (kevät 2016) Ensimmäinen välikoe, malliratkaisut 1. Palautetaan vielä mieleen O-notaation määritelmä. Olkoon f ja g funktioita luonnollisilta luvuilta positiivisille
LisätiedotLuento 7: Lokaalit valaistusmallit
Tietokonegrafiikan perusteet T-111.4300 3 op Luento 7: Lokaalit valaistusmallit Lauri Savioja 11/07 Lokaalit valaistusmallit / 1 Sävytys Interpolointi Sisältö Lokaalit valaistusmallit / 2 1 Varjostustekniikat
LisätiedotTietokonegrafiikka. Jyry Suvilehto T Johdatus tietoliikenteeseen ja multimediatekniikkaan kevät 2014
Tietokonegrafiikka Jyry Suvilehto T-110.1100 Johdatus tietoliikenteeseen ja multimediatekniikkaan kevät 2014 1. Sovellusalueita 2. Rasterigrafiikkaa 3. Vektorigrafiikkaa 4. 3D-grafiikkaa 1. Säteenheitto
LisätiedotLieriö ja särmiö Tarkastellaan pintaa, joka syntyy, kun tasoa T leikkaava suora s liikkuu suuntansa
Lieriö ja särmiö Tarkastellaan pintaa, joka syntyy, kun tasoa T leikkaava suora s liikkuu suuntansa säilyttäen pitkin tason T suljettua käyrää (käyrä ei leikkaa itseään). Tällöin suora s piirtää avaruuteen
LisätiedotPong-peli, vaihe Aliohjelman tekeminen. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 3/7. Tämän vaiheen aikana
Muilla kielillä: English Suomi Pong-peli, vaihe 3 Tämä on Pong-pelin tutoriaalin osa 3/7. Tämän vaiheen aikana Jaetaan ohjelma pienempiin palasiin (aliohjelmiin) Lisätään peliin maila (jota ei voi vielä
LisätiedotTampereen yliopisto Tietokonegrafiikka 2013 Tietojenkäsittelytiede Harjoitus
Tampereen yliopisto Tietokonegrafiikka 2013 Tietojenkäsittelytiede Harjoitus 2 7.2.2013 1. Matematiikan lukiokurssissa on esitetty, että ylöspäin aukeavan paraabelin f(x) = ax 2 +bx+c,a > 0,minimikohtasaadaan,kunf
LisätiedotReaaliaikaiset varjoalgoritmit. Atso Kauppinen
Reaaliaikaiset varjoalgoritmit Atso Kauppinen Tampereen yliopisto Tietojenkäsittelytieteiden laitos Tietojenkäsittelyoppi Pro gradu -tutkielma Maaliskuu 2008 Tampereen yliopisto Tietojenkäsittelytieteiden
LisätiedotVEKTORIANALYYSIN HARJOITUKSET: VIIKKO 4
VEKTORIANALYYSIN HARJOITUKSET: VIIKKO 4 Jokaisen tehtävän jälkeen on pieni kommentti tehtävään liittyen Nämä eivät sisällä mitään kovin kriittistä tietoa tehtävään liittyen, joten niistä ei tarvitse välittää
LisätiedotTIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli
TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op Assembly ja konekieli Tietokoneen ja ohjelmiston rakenne Loogisilla piireillä ja komponenteilla rakennetaan prosessori ja muistit Prosessorin rakenne
LisätiedotMAB3 - Harjoitustehtävien ratkaisut:
MAB3 - Harjoitustehtävien ratkaisut: 1 Funktio 1.1 Piirretään koordinaatistoakselit ja sijoitetaan pisteet: 1 1. a) Funktioiden nollakohdat löydetään etsimällä kuvaajien ja - akselin leikkauspisteitä.
LisätiedotDigikuvan peruskäsittelyn. sittelyn työnkulku. Soukan Kamerat 22.1.2007. Soukan Kamerat/SV
Digikuvan peruskäsittelyn sittelyn työnkulku Soukan Kamerat 22.1.2007 Sisält ltö Digikuvan siirtäminen kamerasta tietokoneelle Skannaus Kuvan kääntäminen Värien säätö Sävyjen säätö Kuvan koko ja resoluutio
Lisätiedot815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset
815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 2 vastaukset Harjoituksen aiheena on BNF-merkinnän käyttö ja yhteys rekursiivisesti etenevään jäsentäjään. Tehtävä 1. Mitkä ilmaukset seuraava
LisätiedotDemo 1: Simplex-menetelmä
MS-C2105 Optimoinnin perusteet Malliratkaisut 3 Ehtamo Demo 1: Simplex-menetelmä Muodosta lineaarisen tehtävän standardimuoto ja ratkaise tehtävä taulukkomuotoisella Simplex-algoritmilla. max 5x 1 + 4x
LisätiedotHelsingin seitsemäsluokkalaisten matematiikkakilpailu 7.2.2013 Ratkaisuita
Helsingin seitsemäsluokkalaisten matematiikkakilpailu..013 Ratkaisuita 1. Eräs kirjakauppa myy pokkareita yhdeksällä eurolla kappale, ja siellä on meneillään mainoskampanja, jossa seitsemän sellaista ostettuaan
LisätiedotLIITE 1 1. Tehtävänä on mallintaa kitara ohjeiden mukaan käyttäen Edit Poly-tekniikkaa.
LIITE 1 1 HARJOITUS 1 Kitara Tehtävänä on mallintaa kitara ohjeiden mukaan käyttäen Edit Poly-tekniikkaa. Käsiteltävät asiat Edit Poly Muokkaus kuvan mukaan TurboSmooth Extrude 1. Tarkistetaan että mittayksiköt
LisätiedotYleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.
2. Taulukot 2.1 Sisältö Yleistä. Esittely ja luominen. Alkioiden käsittely. Kaksiulotteinen taulukko. Taulukko operaation parametrina. Taulukko ja HelloWorld-ohjelma. Taulukko paluuarvona. 2.2 Yleistä
LisätiedotRatkaisu: Maksimivalovoiman lauseke koostuu heijastimen maksimivalovoimasta ja valonlähteestä suoraan (ilman heijastumista) tulevasta valovoimasta:
LASKUHARJOITUS 1 VALAISIMIEN OPTIIKKA Tehtävä 1 Pistemäinen valonlähde (Φ = 1000 lm, valokappaleen luminanssi L = 2500 kcd/m 2 ) sijoitetaan 15 cm suuruisen pyörähdysparaboloidin muotoisen peiliheijastimen
LisätiedotMatematiikan tukikurssi
Matematiikan tukikurssi Kurssikerta 2 Lisää osamurtoja Tutkitaan jälleen rationaalifunktion P(x)/Q(x) integrointia. Aiemmin käsittelimme tapauksen, jossa nimittäjä voidaan esittää muodossa Q(x) = a(x x
LisätiedotPong-peli, vaihe Aliohjelmakutsu laskureita varten. 2. Laskurin luominen. Muilla kielillä: English Suomi
Muilla kielillä: English Suomi Pong-peli, vaihe 7 Tässä vaiheessa lisäämme peliin pistelaskun. Pong-pelissä pelaaja saa pisteen kun pallo ohittaa toisen pelaajan mailan. 1. Aliohjelmakutsu laskureita varten
LisätiedotKäyttöliittymän muokkaus
Käyttöliittymän muokkaus Ohjelman pitkän kehityshistorian takia asetukset ovat jakaantuneet useampaan eri kohtaan ohjelmassa. Ohessa yhteenveto nykyisistä asetuksista (versio 6.4.1, 2/2018). Ylä- ja sivupalkkien
LisätiedotMatopeli C#:lla. Aram Abdulla Hassan. Ammattiopisto Tavastia. Opinnäytetyö
Matopeli C#:lla Aram Abdulla Hassan Ammattiopisto Tavastia Opinnäytetyö Syksy 2014 1 Sisällysluettelo 1. Johdanto... 3 2. Projektin aihe: Matopeli C#:lla... 3 3. Projektissa käytetyt menetelmät ja työkalut
LisätiedotMerkkijono määritellään kuten muutkin taulukot, mutta tilaa on varattava yksi ylimääräinen paikka lopetusmerkille:
Merkkijonot C-kielessä merkkijono on taulukko, jonka alkiot ovat char -tyyppiä. Taulukon viimeiseksi merkiksi tulee merkki '\0', joka ilmaisee merkkijonon loppumisen. Merkkijono määritellään kuten muutkin
LisätiedotZeon PDF Driver Trial
Matlab-harjoitus 2: Kuvaajien piirto, skriptit ja funktiot. Matlabohjelmoinnin perusteita Numeerinen integrointi trapezoidaalimenetelmällä voidaan tehdä komennolla trapz. Esimerkki: Vaimenevan eksponentiaalin
Lisätiedot2.1. Tehtävänä on osoittaa induktiolla, että kaikille n N pätee n = 1 n(n + 1). (1)
Approbatur 3, demo, ratkaisut Sovitaan, että 0 ei ole luonnollinen luku. Tällöin oletusta n 0 ei tarvitse toistaa alla olevissa ratkaisuissa. Se, pidetäänkö nollaa luonnollisena lukuna vai ei, vaihtelee
Lisätiedot