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

Rohamcsiga (vitalap | szerkesztései)
Elkezdtem megírni a negyedik házihoz szükséges elmélet részt. Bocs a self-promó rész miatt...
Rohamcsiga (vitalap | szerkesztései)
Elkezdtem megírni a 3D-s kocka részt.
1 300. sor: 1 300. sor:
* A videókártya segítségével ez még messze nem a maximum amit el lehet érni, a nagyházim kódja egyáltalán nincs is optimalizálva.
* A videókártya segítségével ez még messze nem a maximum amit el lehet érni, a nagyházim kódja egyáltalán nincs is optimalizálva.
* 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 az első meg a második háziban, 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 az első meg a második háziban, csak 3D-ben).
=== 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. Itt kézenfekvő lenne quadokat használni, de én a háromszögeket jobban szeretem (meg amúgy az OpenGL is) :)
<br/> <syntaxhighlight lang="c">
void glVertex3f(const Vector& v) {
  glVertex3f(v.x, v.y, v.z);
}
void glTriangle(const Vector& a, const Vector& b, const Vector& c) {
  glVertex3f(a); glVertex3f(b); glVertex3f(c);
}
void drawCube(const Vector& size) {
  glBegin(GL_TRIANGLES); {
    /*      (E)-----(A)
            /|      /|
            / |    / |
          (F)-----(B) |
          | (H)---|-(D)
          | /    | /
          |/      |/
          (G)-----(C)        */
    Vector s = size / 2;
    Vector A(+s.x, +s.y, -s.z), B(+s.x, +s.y, +s.z), C(+s.x, -s.y, +s.z), D(+s.x, -s.y, -s.z),
          E(-s.x, +s.y, -s.z), F(-s.x, +s.y, +s.z), G(-s.x, -s.y, +s.z), H(-s.x, -s.y, -s.z);
    glTriangle(A, D, B);  glTriangle(C, B, D);  glTriangle(A, B, E);  glTriangle(F, E, B);
    glTriangle(B, C, F);  glTriangle(G, F, C);  glTriangle(F, G, E);  glTriangle(H, E, G);
    glTriangle(H, G, D);  glTriangle(C, D, G);  glTriangle(E, H, A);  glTriangle(D, A, H);
  } glEnd();
}
</syntaxhighlight> <br/>
* Az eredménye: [http://pastebin.com/BJTRSTgm Egy négyzet]
http://i.imgur.com/iWkEuQj.png
* Na várjunk csak, mi egy kockát rajzoltattunk ki a kamerával, 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!
*** 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 pontja 1 mélység koordinátákkal rendelkeznek. kb. 10 sor 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>
**** 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.
***** 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">
void onInitialization() {
  glMatrixMode(GL_PROJECTION);
  gluPerspective(60, 1, 0.1, 10);
  glMatrixMode(GL_MODELVIEW);
}
</syntaxhighlight> <br/>
* Az eredménye: [http://pastebin.com/KVP1YQQs Egy teljesen fehér kép]
http://i.imgur.com/2B4efRi.png
* 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
* 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.


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