„Számítógépes grafika házi feladat tutorial” változatai közötti eltérés
a elgépelések javítása |
|||
| (14 közbenső módosítás, amit 4 másik szerkesztő végzett, nincs mutatva) | |||
| 34. sor: | 34. sor: | ||
** <code>onIdle()</code> - Ez a függvény az idő múlását hivatott jelezni, így itt kell kezelni mindent ami az időtől függ (animáció). | ** <code>onIdle()</code> - Ez a függvény az idő múlását hivatott jelezni, így itt kell kezelni mindent ami az időtől függ (animáció). | ||
== | == 2D OpenGL == | ||
=== Rajzolás az OpenGL segítségével === | === Rajzolás az OpenGL segítségével === | ||
Az OpenGL | Az OpenGL csak néhány típusú primitívet tud rajzolni, ezekből kell építkeznünk. A típusok: | ||
* Pontok: <code>GL_POINTS</code> | * Pontok: <code>GL_POINTS</code> | ||
* Vonalak: <code>GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP</code> | * Vonalak: <code>GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP</code> | ||
| 100. sor: | 100. sor: | ||
glVertex2f(center_x, center_y); | glVertex2f(center_x, center_y); | ||
for(int i = 0; i < | for(int i = 0; i < CIRCLE_RESOLUTION; i++) { | ||
float angle = float(i) / CIRCLE_RESOLUTION * 2.0f * M_PI; | float angle = float(i) / CIRCLE_RESOLUTION * 2.0f * M_PI; | ||
// Itt a kor paramtetrikus alakjat hasznaljuk: x = x0 + r*cos(t), y = y0 + r * sin(t) | // Itt a kor paramtetrikus alakjat hasznaljuk: x = x0 + r*cos(t), y = y0 + r * sin(t) | ||
| 114. sor: | 114. sor: | ||
glVertex2f(center_x, center_y); | glVertex2f(center_x, center_y); | ||
for(int i = 0; i < | for(int i = 0; i < CIRCLE_RESOLUTION; i++) { | ||
float angle = float(i) / CIRCLE_RESOLUTION * 2.0f * M_PI; | float angle = float(i) / CIRCLE_RESOLUTION * 2.0f * M_PI; | ||
glColor3f(0.0f, 0.5f + 0.5f*cos(angle), 0.5f + 0.5f*sin(angle)); | glColor3f(0.0f, 0.5f + 0.5f*cos(angle), 0.5f + 0.5f*sin(angle)); | ||
| 137. sor: | 137. sor: | ||
http://i.imgur.com/6yfh7q2.png | http://i.imgur.com/6yfh7q2.png | ||
=== Eseménykezelés === | === Eseménykezelés === | ||
| 259. sor: | 258. sor: | ||
http://i.imgur.com/ezFQ4l4.png | http://i.imgur.com/ezFQ4l4.png | ||
=== Koordináta rendszerek === | === Koordináta rendszerek === | ||
Az | Az korábbi példákban valószínűleg feltűnt, hogy a pontok NDC (normalizált eszköz koordináta) megadása nem túl kényelmes, még akkor se ha, a világnak mindig ugyanazt a részét nézzük. De mit tegyük akkor, ha a képzeletbeli kamera amivel "lefényképezzük" a jelenetet mozoghat, sőt akár még foroghat is. Az OpenGL kitalálóinak az ötlete az volt erre, hogy a kamera mindig maradjon egy helyben, de ha pl. balra akarnánk forgatni, akkor helyette inkább a világ forogjon jobbra, a kamera viszont maradjon ugyanott, ezzel is ugyanazt a hatást érjük el. Első ránézésre nem látszik, hogy ez miért jó, de ez valójában egy nagyon jó ötlet. Szerencsére ha a világot el kell forgatnunk, akkor nem kell minden egyes pontot nekünk külön-külön elforgatni egy ronda trigonometrikus képlet alapján, ezt rábízhatjuk az OpenGL-re is, hogy mindig mielőtt rajzolna, azelőtt végezzen el valamilyen transzformációt a pontokat amiket kapott. | ||
A grafikában általában affin (egyenestartó) transzformációkat szoktunk használni, a vetítéseket leszámítva. Ezeket a transzformációkat a legkényelmesebb a mátrixuk segítségével tudjuk megadni, több egymás utáni transzformáció pedig egyszerűen a mátrixok szorzatát jelenti. Viszont fontos megjegyezni, hogy 3D-ben az eltolás nem lineáris transzformáció, és nem is lehet mátrixszal felírni. Pedig erre a műveletre biztos, hogy szükségünk lesz. Ennek kiküszöbölésére használhatunk 4D-be 'w' = 1 koordinátával beágyazott 3D-s koordináta-rendszert, ahol az eltolás is egy lineáris trafó. | A grafikában általában affin (egyenestartó) transzformációkat szoktunk használni, a vetítéseket leszámítva. Ezeket a transzformációkat a legkényelmesebb a mátrixuk segítségével tudjuk megadni, több egymás utáni transzformáció pedig egyszerűen a mátrixok szorzatát jelenti. Viszont fontos megjegyezni, hogy 3D-ben az eltolás nem lineáris transzformáció, és nem is lehet mátrixszal felírni. Pedig erre a műveletre biztos, hogy szükségünk lesz. Ennek kiküszöbölésére használhatunk 4D-be 'w' = 1 koordinátával beágyazott 3D-s koordináta-rendszert, ahol az eltolás is egy lineáris trafó. | ||
| 342. sor: | 338. sor: | ||
Tanulság: általában az eltolás - forgatás - nagyítás sorrendet szeretjük. Ez nem jelenti azt, hogy más sorrendnek ne lenne értelme, vagy egy konkrét problémának ne lehetne egyszerűbb megoldása másmilyen sorrendet használva. | Tanulság: általában az eltolás - forgatás - nagyítás sorrendet szeretjük. Ez nem jelenti azt, hogy más sorrendnek ne lenne értelme, vagy egy konkrét problémának ne lehetne egyszerűbb megoldása másmilyen sorrendet használva. | ||
De egy probléma még felmerül, a transzformációk hatása permanens, azaz, ha egyszer elforgattad a világot, akkor az úgy marad, amíg vissza nem forgatod. Tehát ha egy objektum kirajzolása miatt akarsz használni egy transzformációt akkor a rajzolás után azt mindenképpen, mindig vissza is kell csinálnod. De mi van ha egy összetett objektum kirajzolásához akár több száz transzformáció is kellet? Akkor a végén az összeset | De egy probléma még felmerül, a transzformációk hatása permanens, azaz, ha egyszer elforgattad a világot, akkor az úgy marad, amíg vissza nem forgatod. Tehát ha egy objektum kirajzolása miatt akarsz használni egy transzformációt akkor a rajzolás után azt mindenképpen, mindig vissza is kell csinálnod. De mi van ha egy összetett objektum kirajzolásához akár több száz transzformáció is kellet? Akkor a végén az összeset egyenként vissza kell csinálni? Nincs erre jobb megoldás? A válasz természetesen az, hogy van, ez a megoldás a mátrix stack. | ||
=== Matrix stack === | === Matrix stack === | ||
| 561. sor: | 557. sor: | ||
http://i.imgur.com/C1iKaHx.gif | http://i.imgur.com/C1iKaHx.gif | ||
== | == Sugárkövetés == | ||
A | A sugárkövetős házinál a programod teljes mértékben a CPU-n fog futni, ami a videókártya segítsége nélkül nagyon meg fog izzadni, hogy a képet előállítsa neked. Az előző feladatokkal ellentétben itt az optimalizálás nagyon sokat segít, egy release build (-O3) és egy debug build (-O0) között akár több mint ötszörös sebességkülönbség is lehet. Ezért, ha éppen nem debuggolsz, mindenképpen release buildet fordíts. | ||
=== A Sugárkövetés alapjai === | === A Sugárkövetés alapjai === | ||
A | A 2D OpenGL-es példaprogramok között volt egy 3D-s is. Most ezzel a témakörrel fogunk foglalkozni. Technikailag abban a példaprogramban a 3D rajzolást a GLUT csinálta helyettünk. De mielőtt belemennénk a részletekbe, hogy pontosan mit is csinált (ezt majd a 3D OpenGL résznél), vegyük észre, mi is ki tudunk rajzolni egy olyan kockát, mint amit a GLUT csinált, akár az OpenGL segítsége nélkül is. | ||
Először gondoljuk át hogy a valóságban hogyan csinálnánk képet egy kockáról. Szükségünk van egy fényforrásra, enélkül garantáltan nem látnánk semmit, és szükségünk van egy ernyőre is (pl: retina), amin a képet felfoghatjuk. Továbbá nem árt, ha van egy kocka is, amit lefényképezhetünk. | Először gondoljuk át hogy a valóságban hogyan csinálnánk képet egy kockáról. Szükségünk van egy fényforrásra, enélkül garantáltan nem látnánk semmit, és szükségünk van egy ernyőre is (pl: retina), amin a képet felfoghatjuk. Továbbá nem árt, ha van egy kocka is, amit lefényképezhetünk. | ||
| 593. sor: | 589. sor: | ||
* Azt is tudnunk kell, hogy melyik iránynak felel meg a felfele ("What's up?"). Kódban pl nevezzük <code>up</code>-nak. | * Azt is tudnunk kell, hogy melyik iránynak felel meg a felfele ("What's up?"). Kódban pl nevezzük <code>up</code>-nak. | ||
* Tegyük fel, hogy téglalap (vagy sík) egységnyi távolságra van a kamerától. Ekkora annak a középpontja: <code>pos + fwd</code>. | * Tegyük fel, hogy téglalap (vagy sík) egységnyi távolságra van a kamerától. Ekkora annak a középpontja: <code>pos + fwd</code>. | ||
* Tudnunk kell még, hogy melyik irány van jobbra. Ezt az előre és a felfele pozícióból ki tudjuk számolni: <code>right = cross(fwd, up)</code> | * Tudnunk kell még, hogy melyik irány van jobbra. Ezt az előre és a felfele pozícióból ki tudjuk számolni: <code>right = cross(fwd, up) // a cross-product a vektor szorzat angolul, a dot-product pedig a skalár szorzat. </code> | ||
* A felfele vektor amit megadtunk nem biztos, hogy merőleges az előre vektorra, pedig nekünk olyanra van szükségünk. Pl: ha rézsútosan előre és lefele nézünk, de az 'up' vektor az ég fele mutat. Ez valójában nem baj, mert a jobbra és előre vektor ismeretében már ki tudjuk számolni a pontos felfele vektort: <code>up = cross(right, fwd)</code>. | * A felfele vektor amit megadtunk nem biztos, hogy merőleges az előre vektorra, pedig nekünk olyanra van szükségünk. Pl: ha rézsútosan előre és lefele nézünk, de az 'up' vektor az ég fele mutat. Ez valójában nem baj, mert a jobbra és előre vektor ismeretében már ki tudjuk számolni a pontos felfele vektort: <code>up = cross(right, fwd)</code>. | ||
* Ha ezek megvannak, akkor ki kell tudnunk számolni, hogy egy (x, y) koordinátájú pixelnek a téglalap (ami most egy 2 egység oldalhosszúságú négyzet) melyik része felel meg. Ezt így tehetjük meg: | * Ha ezek megvannak, akkor ki kell tudnunk számolni, hogy egy (x, y) koordinátájú pixelnek a téglalap (ami most egy 2 egység oldalhosszúságú négyzet) melyik része felel meg. Ezt így tehetjük meg: | ||
| 599. sor: | 595. sor: | ||
<br/> <syntaxhighlight lang="c"> | <br/> <syntaxhighlight lang="c"> | ||
Vector pos_on_plane = Vector( | Vector pos_on_plane = Vector( | ||
(x | (x - Screen::width/2) / (Screen::width/2), | ||
(y | (y - Screen::height/2) / (Screen::height/2), | ||
0 | 0 | ||
); | ); | ||
| 654. sor: | 650. sor: | ||
void capturePixel(float x, float y) { | void capturePixel(float x, float y) { | ||
Vector pos_on_plane = Vector( | Vector pos_on_plane = Vector( | ||
(x - Screen::width/2) / (Screen::width/2), | (x + 0.5f - Screen::width/2) / (Screen::width/2), | ||
(y - Screen::height/2) / (Screen::height/2), | (y + 0.5f - Screen::height/2) / (Screen::height/2), | ||
0 | 0 | ||
); | ); | ||
| 667. sor: | 663. sor: | ||
</syntaxhighlight> <br/> | </syntaxhighlight> <br/> | ||
Megjegyzés: én általában nem ilyen kamerát szoktam használni, de ez ugyanazt az eredményt adja, mint amit a | Megjegyzés: én általában nem ilyen kamerát szoktam használni, de ez ugyanazt az eredményt adja, mint amit a 3D OpenGL résznél fogunk kapni, a gluLookAt() függvény segítségével. | ||
Most már mindent tudunk a sugárkövetésről, azt leszámítva, hogy hogyan kell egy sugarat követni. | Most már mindent tudunk a sugárkövetésről, azt leszámítva, hogy hogyan kell egy sugarat követni. | ||
| 978. sor: | 974. sor: | ||
Technikailag mindkét algoritmust fogjuk használni. A második - bár bonyolultabbnak tűnhet - de irányfényforrásokra csak az módszer működik. Az irányfényforrások ugyanis végtelen távol vannak, ahonnan nem tudok elindulni, viszont a felületi pontból a fény irányába el tudunk. A pontfényforrások esetén viszont az első algoritmus egyszerűbb egy picivel. | Technikailag mindkét algoritmust fogjuk használni. A második - bár bonyolultabbnak tűnhet - de irányfényforrásokra csak az módszer működik. Az irányfényforrások ugyanis végtelen távol vannak, ahonnan nem tudok elindulni, viszont a felületi pontból a fény irányába el tudunk. A pontfényforrások esetén viszont az első algoritmus egyszerűbb egy picivel. | ||
Fontos megjegyezni, hogy például irányfényforrások esetén a sugarat nem indíthatjuk pontosan a felületi pontról, hiszen akkor az ahhoz legközelebbi metszéspont maga a felületi pont lenne amiből indítottuk. Ez persze nem mindig teljesülne, a számolási pontosság miatt, ezért néhol árnyékban lesz, néhol nem. Ezt a jelenséget "árnyék pattanás"-nak hívja a szakirodalom (shadow acne). Ez nagyon jellemző mintázatot okoz, | Fontos megjegyezni, hogy például irányfényforrások esetén a sugarat nem indíthatjuk pontosan a felületi pontról, hiszen akkor az ahhoz legközelebbi metszéspont maga a felületi pont lenne amiből indítottuk. Ez persze nem mindig teljesülne, a számolási pontosság miatt, ezért néhol árnyékban lesz, néhol nem. Ezt a jelenséget "árnyék pattanás"-nak hívja a szakirodalom (shadow acne). Ez nagyon jellemző mintázatot okoz, amit általában könnyű detektálni. Az alábbi kép mutat egy példát erre: | ||
http://i.imgur.com/TeDR81x.png | http://i.imgur.com/TeDR81x.png | ||
| 1 098. sor: | 1 094. sor: | ||
<br/> <syntaxhighlight lang="c"> | <br/> <syntaxhighlight lang="c"> | ||
x = max(0, | x = max(0, InputLuminance-0.004); | ||
OutputLuminance = (x*(6.2*x+0.5))/(x*(6.2*x+1.7)+0.06); | |||
</syntaxhighlight> <br/> | </syntaxhighlight> <br/> | ||
| 1 486. sor: | 1 482. sor: | ||
=== A kétirányú sugárkövetés === | === A kétirányú sugárkövetés === | ||
A globális illumináció implementálásakor sokak fájó szívvel válnak meg a kódban a lokális illumináció résztől, lévén, hogy hiába írták meg, ha nem jó semmire. De ez nem így van. Egyrészt a | A globális illumináció implementálásakor sokak fájó szívvel válnak meg a kódban a lokális illumináció résztől, lévén, hogy hiába írták meg, ha nem jó semmire. De ez nem így van. Egyrészt a 3D OpenGL-es házikhoz nagyon nagy segítséget fog nyújtani, hogy érted, hogy hogyan működik a lokális illumináció, hiszen az OpenGL is ezt fogja használni. Másrészt még a sugárkövetés házi végleges formájába is hasznos lehet az a kód. | ||
A kétirányú sugárkövetés ötlete, hogy használjuk a lokális és a globális illuminációt egyszerre. A diffúz anyagot világítsuk meg lokálisan, és csak azok a fotonok keltsenek rajta kausztikát, amik nem triviális úton (egyenes vonalon, végig a levegőben, kölcsönhatás nélkül) jutottak el a fényforrásból az anyagig. Tehát ha a foton ütközésekor a rekurziós szint 0, akkor az közvetlenül a fényforrásból jutott el hozzánk, azt ne mentsük el. | A kétirányú sugárkövetés ötlete, hogy használjuk a lokális és a globális illuminációt egyszerre. A diffúz anyagot világítsuk meg lokálisan, és csak azok a fotonok keltsenek rajta kausztikát, amik nem triviális úton (egyenes vonalon, végig a levegőben, kölcsönhatás nélkül) jutottak el a fényforrásból az anyagig. Tehát ha a foton ütközésekor a rekurziós szint 0, akkor az közvetlenül a fényforrásból jutott el hozzánk, azt ne mentsük el. | ||
| 1 500. sor: | 1 496. sor: | ||
Példaprogram: ''<Törölve, túl sokan másolták>'' | Példaprogram: ''<Törölve, túl sokan másolták>'' | ||
A korábbi jelenet | A korábbi jelenet kétirányú (bal oldalt) és csak globális (jobb oldalt) megvilágítással, mindkét esetben 500 000 fotonnal | ||
{| | {| | ||
|- | |- | ||
| 1 559. sor: | 1 555. sor: | ||
<br/> | <br/> | ||
== | == 3D OpenGL == | ||
=== Kedvcsináló === | === Kedvcsináló === | ||
| 1 565. sor: | 1 561. sor: | ||
Sugárkövetéssel nagyon látványos képeket tudunk elérni, ha vesszük a fáradtságot, hogy érdekes objektumokat helyezzünk el a világban. Főleg a másodrendű felületek tudnak nagyon szép képeket adni. Az árnyékszámításhoz gyakorlatilag ölünkbe hullott egy algoritmus, amihez pont ugyanazt kellett csinálni, mint amit rajzoláskor is csináltunk. A globális illuminációval ráadásul olyan hatásokat is implementálni tudtunk, amikkel a mai játékokba szinte sehol nem lehet találkozni. Akkor mi a gond a sugárkövetéssel, miért nem ezt használjuk mindenhol, miért kell akkor egyáltalán OpenGL? A probléma az vele, hogy lassú. Az általam mutatott programok mindössze 14 darab háromszögből álltak, messze elmaradva a mai játékok komplexitásától, és így is, a globális illuminációval kb. 5 másodperc volt, mire a kép előállt. Ez nem tűnik soknak, de optimális esetben egy játékhoz másodpercenként legalább 60szor kéne képet alkotnunk, a sugárkövető ettől messze elmarad. Ha a kódot két héten át optimalizáltam volna, akkor akár 0.1 másodperc is lehetne a renderelési idő. Igen ám, de ez csak a képalkotásra szánt idő! A játék logika, főleg ütközés detektálások, vagy ruha-, víz szimuláció stb. egyáltalán nincsenek ingyen, és még azoknak is bele kéne férnie az időbe. És ez még mindig csak 14 darab háromszög. | Sugárkövetéssel nagyon látványos képeket tudunk elérni, ha vesszük a fáradtságot, hogy érdekes objektumokat helyezzünk el a világban. Főleg a másodrendű felületek tudnak nagyon szép képeket adni. Az árnyékszámításhoz gyakorlatilag ölünkbe hullott egy algoritmus, amihez pont ugyanazt kellett csinálni, mint amit rajzoláskor is csináltunk. A globális illuminációval ráadásul olyan hatásokat is implementálni tudtunk, amikkel a mai játékokba szinte sehol nem lehet találkozni. Akkor mi a gond a sugárkövetéssel, miért nem ezt használjuk mindenhol, miért kell akkor egyáltalán OpenGL? A probléma az vele, hogy lassú. Az általam mutatott programok mindössze 14 darab háromszögből álltak, messze elmaradva a mai játékok komplexitásától, és így is, a globális illuminációval kb. 5 másodperc volt, mire a kép előállt. Ez nem tűnik soknak, de optimális esetben egy játékhoz másodpercenként legalább 60szor kéne képet alkotnunk, a sugárkövető ettől messze elmarad. Ha a kódot két héten át optimalizáltam volna, akkor akár 0.1 másodperc is lehetne a renderelési idő. Igen ám, de ez csak a képalkotásra szánt idő! A játék logika, főleg ütközés detektálások, vagy ruha-, víz szimuláció stb. egyáltalán nincsenek ingyen, és még azoknak is bele kéne férnie az időbe. És ez még mindig csak 14 darab háromszög. | ||
A általunk használt sugárkövetéssel a legnagyobb gond az, hogy nem használja a videókártyát. Hiába van a gépünkbe egy szuperszámítógép teljesítményű hardware, ha nem használjuk semmire. A mai videókártyák nem csak előre meghatározott műveletek tudnak végrehajtani, hanem már programozhatóak is. Az ezt kihasználó grafikus programok hihetetlen hatékonyak. Például az én grafika nagyházim egy 72 millió | A általunk használt sugárkövetéssel a legnagyobb gond az, hogy nem használja a videókártyát. Hiába van a gépünkbe egy szuperszámítógép teljesítményű hardware, ha nem használjuk semmire. A mai videókártyák nem csak előre meghatározott műveletek tudnak végrehajtani, hanem már programozhatóak is. Az ezt kihasználó grafikus programok hihetetlen hatékonyak. Például az én grafika nagyházim egy 72 millió háromszögből álló jelenetet tudott valós időben (kb. 20 FPS-el) kirajzolni (fizikával együtt). | ||
<div style="text-align:center;margin:0px auto;"> | <div style="text-align:center;margin:0px auto;"> | ||
http://i.imgur.com/ | http://i.imgur.com/zYUuZ0L.png | ||
</div> | </div> | ||
Csak emlékeztetőül, sugárkövetéssel 14 háromszög nem ment valós időben... A videókártya segítségével a 72 millió | Csak emlékeztetőül, sugárkövetéssel 14 háromszög nem ment valós időben... A videókártya segítségével a 72 millió háromszögből álló jelenet real-time kirajzolása még messze nem a maximum amit el lehet érni. | ||
A videókártyát használhatnánk arra, hogy gyors raytracert írjunk. Ehhez viszont meg kellene tanulni, hogy hogyan kell a videókártyát programozni... Ehelyett mi a videókártya kezelését az OpenGLre bízzuk, és az inkrementális elvet használva fogunk rajzolni (ugyanúgy, mint | A videókártyát használhatnánk arra, hogy gyors raytracert írjunk. Ehhez viszont meg kellene tanulni, hogy hogyan kell a videókártyát programozni... Ehelyett mi a videókártya kezelését az OpenGLre bízzuk, és az inkrementális elvet használva fogunk rajzolni (ugyanúgy, mint a 2D OpenGL-es résznél, csak 3D-ben). | ||
=== A 3D-s kocka === | === A 3D-s kocka === | ||
A | A 2D OpenGL-es résznél mutattam egy glut függvényt, ami egy kockát rajzol ki. Ezt a házikhoz nem lehet használni, inkább írjunk meg magunknak. | ||
<br/> <syntaxhighlight lang="c"> | <br/> <syntaxhighlight lang="c"> | ||
| 1 623. sor: | 1 620. sor: | ||
A függvény amit használhatunk az a <code> gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)</code>. Megjegyzések a paramétérek megválasztásához: | A függvény amit használhatunk az a <code> gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)</code>. Megjegyzések a paramétérek megválasztásához: | ||
* A fov-ot szögben, nem radiánba kell megadnunk. A reális értéke 40 - 150 fok között mozog. | * A fov-ot szögben, nem radiánba kell megadnunk. A reális értéke 40 - 150 fok között mozog. | ||
* Az ascpect a képernyő szélessége / képernyő magassága. A házikba | * Az ascpect a képernyő szélessége / képernyő magassága. A házikba ennek az értéke egy. | ||
* A zNear-nél sokan nagy késztetést éreznek, hogy egy nagyon kicsi értéket állítsanak be, hogy semmi se kerüljön az első vágósík elé. A gond viszont ezzel az, hogy az mélység számító algoritmus a természeténél fogva több különböző ponthoz is ugyanazt az értéket rendeli, hiszen csak egy véges tartományt használhat (általában egy 24 bites fixpontos számot). Amiért ez zavaró, az az, hogy minél nagyobb a zFar / zNear értéke, annál nagyobb tartományt kell ugyanarra a (0..1) intervallumra transzformálni. Ez pedig azzal jár hogy az egyre távolabb lévő pontokhoz is ugyanazt a mélységet fogja használni. Ilyenkor pedig nem tudjuk eldönteni, hogy mi látszódik, és mi nem, aminek szinte mindig nagyon ronda eredménye szokott lenni. Egy ökölszabály, hogy a zFar / zNear értéke ne legyen (sokkal) nagyobb 1000-nél. A házikhoz tipikusan nincs szükség 100-nál nagyobb zFar-ra, ilyenkor a zNear ne legyen 0.1-nél kisebb. | * A zNear-nél sokan nagy késztetést éreznek, hogy egy nagyon kicsi értéket állítsanak be, hogy semmi se kerüljön az első vágósík elé. A gond viszont ezzel az, hogy az mélység számító algoritmus a természeténél fogva több különböző ponthoz is ugyanazt az értéket rendeli, hiszen csak egy véges tartományt használhat (általában egy 24 bites fixpontos számot). Amiért ez zavaró, az az, hogy minél nagyobb a zFar / zNear értéke, annál nagyobb tartományt kell ugyanarra a (0..1) intervallumra transzformálni. Ez pedig azzal jár hogy az egyre távolabb lévő pontokhoz is ugyanazt a mélységet fogja használni. Ilyenkor pedig nem tudjuk eldönteni, hogy mi látszódik, és mi nem, aminek szinte mindig nagyon ronda eredménye szokott lenni. Egy ökölszabály, hogy a zFar / zNear értéke ne legyen (sokkal) nagyobb 1000-nél. A házikhoz tipikusan nincs szükség 100-nál nagyobb zFar-ra, ilyenkor a zNear ne legyen 0.1-nél kisebb. | ||
| 1 817. sor: | 1 814. sor: | ||
http://i.imgur.com/iZJlFr9.gif | http://i.imgur.com/iZJlFr9.gif | ||
* A megvilágítást közvetlenül a setCamera() függvény után állítjuk be. Ekkora a glLightfv-ben megadott pozíció a világ koordináta-rendszerben lesz értelmezve, és a statikus objektumoknak "mindig ugyanaz oldala lesz fényes". Ezt általában akkor szoktuk használni, ha a fényforrás a jelentben egy helyben marad. | * A megvilágítást közvetlenül a setCamera() függvény után állítjuk be. Ekkora a glLightfv-ben megadott pozíció a világ koordináta-rendszerben lesz értelmezve, és a statikus objektumoknak "mindig ugyanaz az oldala lesz fényes". Ezt általában akkor szoktuk használni, ha a fényforrás a jelentben egy helyben marad. | ||
http://i.imgur.com/cUPVzeT.gif | http://i.imgur.com/cUPVzeT.gif | ||
| 2 188. sor: | 2 185. sor: | ||
Viszont ezzel nehézkes a debuggolás, nem lehet igazán jól körülnézni, és valós játékokban is ritka az ennyire egyszerű kamera. | Viszont ezzel nehézkes a debuggolás, nem lehet igazán jól körülnézni, és valós játékokban is ritka az ennyire egyszerű kamera. | ||
Én egy egyszerű szabadon-repülő kamera egy implementációjához adok ötletet, | Én egy egyszerű, szabadon-repülő kamera egy implementációjához adok ötletet, ami sokat segíthet a debuggoláshoz (sokszor csak egy nézetből nézve egy jelenetet nem lehet eldönteni, hogy az jó-e). | ||
Kétféle input érdekel minket, a billentyűlenyomások (W,A,S,D), és az egér mozgatása (úgy, hogy közbe az egyik egérgomb le van nyomva). | Kétféle input érdekel minket, a billentyűlenyomások (W,A,S,D), és az egér mozgatása (úgy, hogy közbe az egyik egérgomb le van nyomva). | ||
A billentyűlenyomásokat nem kezelhetjük egyszerűen az onKeyboard-ban, ez akkor generál eseményeket, amikor egy karaktert begépelnénk, ami pl megtörténik először a billentyű lenyomásakor, aztán jelentős ideig (kb. 0.3 - 0.5 sec) nem generálódik újabb esemény, majd után másodpercenként kb. 10-20 karakterbeütés-t generál. | A billentyűlenyomásokat nem kezelhetjük egyszerűen az onKeyboard-ban, ez akkor generál eseményeket, amikor egy karaktert begépelnénk, ami pl megtörténik először a billentyű lenyomásakor, aztán jelentős ideig (kb. 0.3 - 0.5 sec) nem generálódik újabb esemény, majd után másodpercenként kb. 10-20 karakterbeütés-t generál. Ez pl egy karakter irányításához teljesen használhatatlan, helyette inkább tároljuk el, hogy az egyes billentyűk lenyomott állapotban vannak-e. | ||
<br/> <syntaxhighlight lang="c"> | <br/> <syntaxhighlight lang="c"> | ||
| 2 321. sor: | 2 318. sor: | ||
Az én implementációim: [[Média:Grafpp4_kamera.cpp|Kamera]] | Az én implementációim: [[Média:Grafpp4_kamera.cpp|Kamera]] | ||
[[ | [[File:Graftutorial_kamera_anim.gif]] | ||
== Utóhang == | == Utóhang == | ||
| 2 328. sor: | 2 325. sor: | ||
----- | ----- | ||
[https://wiki.sch.bme.hu/Szerkeszt%C5%91:Rohamcsiga | [https://wiki.sch.bme.hu/Szerkeszt%C5%91:Rohamcsiga Csala Tamás] - 2014.01. | ||
[[Category:Infoalap]] | [[Category:Infoalap]] | ||