„Számítógépes grafika házi feladat tutorial” változatai közötti eltérés

Rohamcsiga (vitalap | szerkesztései)
 
(9 közbenső módosítás, amit 2 másik szerkesztő végzett, nincs mutatva)
100. sor: 100. sor:
   glVertex2f(center_x, center_y);
   glVertex2f(center_x, center_y);


   for(int i = 0; i <= CIRCLE_RESOLUTION; 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 <= CIRCLE_RESOLUTION; 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 ===
590. 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:
596. sor: 595. sor:
<br/> <syntaxhighlight lang="c">  
<br/> <syntaxhighlight lang="c">  
Vector pos_on_plane = Vector(
Vector pos_on_plane = Vector(
   (x + 0.5f - Screen::width/2) / (Screen::width/2),
   (x - Screen::width/2) / (Screen::width/2),
   (y + 0.5f - Screen::height/2) / (Screen::height/2),  
   (y - Screen::height/2) / (Screen::height/2),  
   0
   0
);
);
651. 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
     );
     );
1 095. sor: 1 094. sor:


<br/> <syntaxhighlight lang="c">
<br/> <syntaxhighlight lang="c">
   x = max(0, InputColor-0.004);
   x = max(0, InputLuminance-0.004);
   OutputColor = (x*(6.2*x+0.5))/(x*(6.2*x+1.7)+0.06);
   OutputLuminance = (x*(6.2*x+0.5))/(x*(6.2*x+1.7)+0.06);
</syntaxhighlight> <br/>
</syntaxhighlight> <br/>


1 497. 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, csak kétirányú (bal oldalt) és baloldalt (jobb oldalt) sugárkövetéssel, mindkét esetben 500 000 fotonnal
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 562. 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ó háromszögból álló jelenetet tudott valós időben (kb. 25 FPS-el) kirajzolni.
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/fGQv8Wp.png
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ó háromszög real-time kirajzolása még messze nem a maximum amit el lehet érni, a nagyházim kódja egyáltalán nincs is optimalizálva.
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 2D OpenGL-es résznél, csak 3D-ben).
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).
1 814. 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 189. sor: 2 189. sor:
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. És ez nekünk nagyon jó, helyette inkább tároljuk el, hogy az egyes billentyűk mikor vannak lenyomott állapotban.
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 318. 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]]  


[[Fájl:Graftutorial_kamera_anim.gif]]
[[File:Graftutorial_kamera_anim.gif]]


== Utóhang ==
== Utóhang ==