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

Rohamcsiga (vitalap | szerkesztései)
Rohamcsiga (vitalap | szerkesztései)
1 547. sor: 1 547. sor:


=== A 3D-s kocka ===
=== A 3D-s kocka ===
* A második házinál mutattam egy glut függvényt, ami egy kockát rajzol ki. Ezt a házikhoz nem lehet használni, inkább írjunk egyet magunknak.  
 
A második házinál mutattam egy glut függvényt, ami egy kockát rajzol ki. Ezt a házikhoz nem lehet használni, inkább írjunk egyet magunknak.  


<br/> <syntaxhighlight lang="c">
<br/> <syntaxhighlight lang="c">
1 581. sor: 1 582. sor:
</syntaxhighlight> <br/>
</syntaxhighlight> <br/>


* Az eredménye: [[Média:Grapp4_negyzet.cpp‎|Egy négyzet]]
Az eredménye: [[Média:Grapp4_negyzet.cpp‎|Egy négyzet]]
 
http://i.imgur.com/iWkEuQj.png
http://i.imgur.com/iWkEuQj.png
* Na várjunk csak, mi egy kockát rajzoltattunk ki, akkor miért egy négyzetet látunk? Azért mert kameránál a "fényképezést", mint transzformációt leíró mátrix (a GL_PROJECTION) egy egységmátrix, így a fényképezés egyszerűen a z koordináta eldobására korlátozódik. A kockának mindössze két oldala van, aminek az XY síkra vett vetülete nem nulla területű, de mindkét vetület egy-egy négyzet. Mi a kettő közül a később kirajzolt oldalnak a vetületét látjuk.
 
** A megoldás: Állítsuk be a projekciós mátrixot!
Na várjunk csak, mi egy kockát rajzoltattunk ki, akkor miért egy négyzetet látunk? Azért mert kameránál a "fényképezést", mint transzformációt leíró mátrix (a GL_PROJECTION) egy egységmátrix, így a fényképezés egyszerűen a z koordináta eldobására korlátozódik. A kockának mindössze két oldala van, aminek az XY síkra vett vetülete nem nulla területű, de mindkét vetület egy-egy négyzet. Mi a kettő közül a később kirajzolt oldalnak a vetületét látjuk.
*** Első közelítésként próbálkozhatnánk a sugárkövetésnél használt fényképezés leírásával. Ez részben működne, az algoritmus bemenete a látószög (FoV), és a képernyő szélességének és magasságának az aránya, és ezekből meghatározza a képen az X és Y koordinátákat. Ez a transzformáció önmagában viszont nekünk nem elég, mert a láthatóság eldöntése miatt szükségünk van egy 'z' koordinátára is, amibe azt akarjuk eltárolni, hogy az adott objektum milyen távol van a kamerától (előjelesen, a kamera nézeti iránya a pozitív). De ez az érték a (-végtelen, végtelen) tartományon mozog, amit mi a (-1, 1) tartományra akarunk transzformálni. Ilyen problémával már találkoztunk, a tonemappingnél,  és két lehetséges megoldást is mutattam rá. De itt egyik se működik. Az ötlet ami itt szoktunk használni, az az, hogy egy bizonyos távolságnál (zNear) közelebb lévő és egy másik távolságnál (zFar) pedig a távolabb lévő objektumokat nem rajzoljuk ki. Ez gyakorlatban egy elég jól alátámasztható döntés, ha egy objektumokkal teli zsúfolt világban végtelen távolra ellátnánk, akkor végtelen erőforrásra is szükségünk lenne ahhoz, hogy arról képet alkossunk. A szemünkhöz nagyon közeli objektumok pedig olyan nagynak látszódnának, hogy nem látnánk tőlük semmi mást. A két távolság két vágósíkot határoz meg. Egy transzformáció kell nekünk, amire egy a közeli vágósíkon lévő objektum 'z' koordinátája 0 lesz, míg a távoli vágósík pontjai 1 mélység koordinátákkal rendelkeznek. Kb. 10 sor lenne levezetni az ezt megvalósító transzformáció mátrixát, de ettől megkíméllek titeket, mert a házihoz úgy sincs rá szükség, ugyanis egy glu függvény ezt megcsinálja helyettünk.
 
*** A függvény amit használhatunk az a <code> gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) </code>
A megoldás: állítsuk be a projekciós mátrixot. Első közelítésként próbálkozhatnánk a sugárkövetésnél használt fényképezés leírásával. Ez részben működne, az algoritmus bemenete a látószög (FoV), és a képernyő szélességének és magasságának az aránya, és ezekből meghatározza a képen az X és Y koordinátákat. Ez a transzformáció önmagában viszont nekünk nem elég, mert a láthatóság eldöntése miatt szükségünk van egy 'z' koordinátára is, amibe azt akarjuk eltárolni, hogy az adott objektum milyen távol van a kamerától (előjelesen, a kamera nézeti iránya a pozitív). De ez az érték a jelenetben a (-végtelen, végtelen) tartományon mozog, amit mi a (-1, 1) tartományra akarunk transzformálni.  
**** 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.
Ilyen problémával már találkoztunk, a tonemappingnél,  és két lehetséges megoldást is mutattam rá. De itt egyik se működik. Az ötlet ami itt szoktunk használni, az az, hogy egy bizonyos távolságnál (zNear) közelebb lévő és egy másik távolságnál (zFar) pedig a távolabb lévő objektumokat nem rajzoljuk ki. Ez gyakorlatban egy elég jól alátámasztható döntés, ha egy objektumokkal teli zsúfolt világban végtelen távolra ellátnánk, akkor végtelen erőforrásra is szükségünk lenne ahhoz, hogy arról képet alkossunk. A szemünkhöz nagyon közeli objektumok pedig olyan nagynak látszódnának, hogy nem látnánk tőlük semmi mást. A két távolság két vágósíkot határoz meg. Egy transzformáció kell nekünk, amire egy a közeli vágósíkon lévő objektum 'z' koordinátája 0 lesz, míg a távoli vágósík pontjai 1 mélység koordinátákkal rendelkeznek. Kb. 10 sor lenne levezetni az ezt megvalósító transzformáció mátrixát, de ettől megkíméllek titeket, mert a házihoz úgy sincs rá szükség, ugyanis egy glu függvény ezt megcsinálja helyettünk.
***** Az ascpect a képernyő szélessége / képernyő magassága. A házikba ez 1.
 
***** 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 ugyan azt 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 ugyan arra a (0..1) intervallumra transzformálni. Ez pedig azzal jár hogy az egyre távolabb lévő pontokhoz is ugyan azt 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.
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:
****** 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 fov-ot szögben, nem radiánba kell megadnunk. A reális értéke 40 - 150 fok között mozog.
*** Például:
* Az ascpect a képernyő szélessége / képernyő magassága. A házikba ez 1.
* 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 ugyan azt 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 ugyan arra a (0..1) intervallumra transzformálni. Ez pedig azzal jár hogy az egyre távolabb lévő pontokhoz is ugyan azt 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.
 
Például:


<br/> <syntaxhighlight lang="c">
<br/> <syntaxhighlight lang="c">
1 602. sor: 1 607. sor:
</syntaxhighlight> <br/>
</syntaxhighlight> <br/>


* A kockát kirajzoló (kirajzolni próbáló) program eredménye ezzel a pár sorral kibővítve: [[Média:Grafpp4_feher_kep.cpp|Egy teljesen fehér kép]]
A kockát kirajzoló (kirajzolni próbáló) program eredménye ezzel a pár sorral kibővítve:  
 
[[Média:Grafpp4_feher_kep.cpp|Egy teljesen fehér kép]]
 
http://i.imgur.com/2B4efRi.png
http://i.imgur.com/2B4efRi.png


* Igen, én képes voltam képes erről feltölteni egy screenshotot.
Igen, én képes voltam képes erről feltölteni egy screenshotot. Én mondtam, hogy sugárkövetéssel látványosabb eredményeket lehet elérni :D
** Én mondtam, hogy sugárkövetéssel látványosabb eredményeket lehet elérni :D
 
* Igazándiból annyira nem meglepő, hogy egy kocka belsejében lévő kamera nem lát mást, mint a kockát, ami jelenleg teljesen fehér.
Igazándiból annyira nem meglepő, hogy egy kocka belsejében lévő kamera nem lát mást, mint a kockát, ami jelenleg teljesen fehér.
* A megoldás: "Rakjuk át a kamerát a kockán kívülre". Pontosabban a világot (és vele a kockát) transzformálúk úgy, hogy a kamera ne legyen a kocka belsejében.
 
** A legkényelmesebb módja: <code> gluLookAt(GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ) </code>
A megoldás: "Rakjuk át a kamerát a kockán kívülre". Pontosabban a világot (és vele a kockát) transzformálúk úgy, hogy a kamera ne legyen a kocka belsejében. A legkényelmesebb módja: <code> gluLookAt(GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ)</code> - hol legyen a kamera, mit nézzen, és melyik legyen a felfele vektor. Például az onInitbe <code> gluLookAt(-3, 2, -2, 0, 0, 0, 0, 1, 0); </code>
*** Hol legyen a kamera, mit nézzen, és melyik legyen a felfele vektor.
* Pl az onInitbe <code> gluLookAt(-3, 2, -2, 0, 0, 0, 0, 1, 0); </code>


http://i.imgur.com/ChgkBk4.png
http://i.imgur.com/ChgkBk4.png
1 629. sor: 1 635. sor:
http://i.imgur.com/o8dUcNz.png
http://i.imgur.com/o8dUcNz.png


* Ez nem túl meggyőző... Azért nem hasonlít egy kockára, mert az oldalak láthatóságát a rajzolás sorrendje döntötte el. De nem azért szenvedtünk a projekciós transzformáció mélység értékével, mert abból az OpenGL meg tudja oldani a láthatóság problémáját? De, csak ezt be kell kapcsolni...
Ez nem túl meggyőző... Azért nem hasonlít egy kockára, mert az oldalak láthatóságát a rajzolás sorrendje döntötte el. De nem azért szenvedtünk a projekciós transzformáció mélység értékével, mert abból az OpenGL meg tudja oldani a láthatóság problémáját? De, csak ezt be kell kapcsolni... Az ezt bekapcsoló függvényhívás: <code> glEnable(GL_DEPTH_TEST)</code>. Fontos, hogy ha ez be van kapcsolva akkor a képernyőt a <code> glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)</code> függvénnyel töröld le. Ha a GL_DEPTH_BUFFER_BIT konstanst lehagyod, akkor nem fogsz látni semmit.
** Az ezt bekapcsoló függvényhívás: <code> glEnable(GL_DEPTH_TEST); </code>
 
*** Fontos, hogy ha ez be van kapcsolva akkor a képernyőt a <code> glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); </code> függvénnyel töröld le. Ha a GL_DEPTH_BUFFER_BIT konstanst lehagyod, akkor nem fogsz látni semmit.
Az eredmény: [[Média:Grafpp4_vegre_egy_kocka.cpp‎|Végre egy kocka!]]


* Az eredmény: [[Média:Grafpp4_vegre_egy_kocka.cpp‎|Végre egy kocka!]]
http://i.imgur.com/z0QQfCD.png
http://i.imgur.com/z0QQfCD.png