2008. 01. 03. vizsga

A VIK Wikiből
(SzgGrafVizsga20080103 szócikkből átirányítva)

Ez az oldal a korábbi SCH wikiről lett áthozva.

Ha úgy érzed, hogy bármilyen formázási vagy tartalmi probléma van vele, akkor, kérlek, javíts rajta egy rövid szerkesztéssel!

Ha nem tudod, hogyan indulj el, olvasd el a migrálási útmutatót.


Infók

  • rendelkezésre álló idő 80 perc.
  • Összesen szerezhető pontok: 40 (=20+10+5+5)
  • A vizsga sikeres = (1. feladat >= 6 pont) && (összes pont >= 16 pont);
  • Ezen a helyen volt linkelve a(z) megooldas.doc nevű fájl ("Hivatalos megoldás" link szöveggel) a régi wiki http://wiki-old.sch.bme.hu/bin/view/Infoalap/SzgGrafVizsga20080103 oldaláról. (Ha szükséged lenne a fájlra, akkor a pontos oldalmegnevezéssel együtt küldd el a wiki@sch.bme.hu címre a kérésedet)


1. feladat

Írjon Color Trace (Vector s, Vector d, int depth) függvényt, amely megkapja a sugár kezdőpontját (s) és irányát (d, amely egység hosszú), a maximális rekurziós mélységet (depth), és kiszámolja a sugár mentén visszafelé haladó fény sugársűrűségét az r,g,b hullámhosszokon. A globális változóval megadott színtér (scene) nsik db síkból áll, amelyek mindkét oldala Phong-Blinn modell szerint spekulárisan (figyelem, nem Phong modellről van szó!) veri vissza a fényt. A sík két oldala ugyanolyan optikai paraméterekkel rendelkezik. Egy, globális változóval megadott irányfényforrás van (light), amely csak a (végtelen távoli) fényforrásból látható felületeket világítja meg (árnyékszámítás kell!).
Pontozás:

  • megoldás elvének leírása képletekkel = 3 pont
  • láthatósági feladat megoldása C++ nyelven = 6 pont
  • spekuláris visszaverődés számítása Phong-Blinn modell szerint C++-ban = 6 pont (Phong modell 0 pontot ér)
  • árnyékszámítás C++-ban = 5 pont
  • Minden olyan program és pszeudokód, amely jelöléseiben vagy funkciójában nem felel meg a kitűzött feladatnak = -10 pont

A felhasználható osztályok:

struct Color{
float r,g,b;
Color (float r0, float g0, float b0){r=r0; g=g0; b=b0;}
Color operator* (Color c){return Color(r*c.r, g*c.g, b*c.b);}
Color operator* (float c){return Color(r*c, g*c, b*c);}
Color operator+ (Color c){return Color(r+c.r, g+c.g, b+c.b);}
};

struct Vector{
float x,y,z;
Vector (float x0, float y0, float z0){x=x0; y=y0; z=z0;}
Vector operator*(float c){return Vector(x*c, y*c, z*c);}
Vector operator+(Vector c){return Vector(x+c.x, y+c.y, z+c.z);}
};

struct Sik{
Vector r0;	//helyvektor Descartes koordinátái
Vector N;	//sík normálvektora (egységhosszú)
Color ks;	//a spekuláris fényvisszaverődési tényező
float shininess;	//a Phong-Blinn modell exponens
} scene[nsik];

struct Feny{
Vector D;	//fényforrás iránya
Color I;	//bejövő sugársűrűség
} light;

A megoldás elve:

A Trace függvény megkeresi azt a síkot melyet a sugár legelőször metsz. A sugár paraméteres egyenlete: r(t)=s+d*t. A sík implicit egyenlete: (r-r0)*N=0. Az előbbit az utóbbiba helyettesítve: (r(t)-r0)*n=0 (s+d*t-r0)*n=0 (s-r0+d*t)*n=0 (s-r0)*n+d*t*n=0 d*n*t=-(s-r0)*n Ebből meghatározható a metszésponthoz tartozó t érték: t=(r0-s)*n / d*n Amiből a metszéspont: p=s+d*t

Ezután a metszéspontból sugarat indít a fényforrás irányával ellentétes irányba, és megnézi az metsz-e más síkot. Ha igen, akkor a pont árnyékban van, nincs abban a pontban direkt megvilágításból érkező fény. Ha nem, akkor a kimenő sugársűrűséghez hozzáadja a direkt megvilágításból származó fény hatását. A Phong-Blinn modell a nézeti irány vektorának (V) és a megvilágítási irány vektorának (L) felezővektora (H=L+V/|L+V) és a felületi normálvektor (N) által bezárt szöggel (fi) számolja a spekulárisan visszavert sugársűrűséget az alábbi módon: Lout=Lin*ks*(cos fi)^shininess. A cos fi skaláris szorzatként is megkapható egységvektorok esetén: cos fi=H*N

A direkt megvilágítás vizsgálata után az ideális visszaverődési irányból érkező sugársűrűségre számolja a spekuláris visszaverődést ugyanilyen módon és ezt is hozzáadja a kimenő sugársűrűséghez. Ehhez a visszaverődés iránya: R=V+2*cos alfa, ahol az alfa a normálvektor és a nézeti irány által bezárt szög. A cos alfa=-N*V skaláris szorzatnak felel meg. A visszaverődési irányból érkező sugársűrűség a függvény rekurzív hívásával kereshető meg, a sugarat a metszéspontból a visszaverődési irány felé indítva. (Persze csak a megadott mélységig)

-- buc - 2008.01.04.

2. feladat

Melyik pixelt változtatja meg az alábbi program?
Pontozás:

  • a pixel x,y koordinátáinak megadása számítással együtt = 10 pont
  • az alábbi sorok jelentésének taglalása = -5 pont
glDisable(GL_DEPTH_TEST);
glViewport(0 /*left*/, 0 /*bottom*/, 200 /*width*/, 200 /*height*/)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90 /*fov*/, 1 /*aspect*/, 1 /*fp*/, 1000 /*bp*/);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0 /*eyex*/, 0 /*eyey*/, 6 /*eyez*/, 0 /*lax*/, 0 /*lay*/, -1 /*laz*/, 0 /*upx*/, 1 /*upy*/, 0 /*upz*/);
glTranslatef(-15.0, -10.0, -49.0);
glBegin(GL_POINTS);
glVertex4f(0, 0, 2, -2);
glEnd();

Megoldás:
Hát ahogy azt már órán számtalanszor hallhattuk, az OpenGL kódot visszafelé kell olvasni. :)
Így:

glBegin(GL_POINTS);
glVertex4f(0, 0, 2, -2);
glEnd();

Felveszünk egy pontot a [0,0,2,-2] koordinátára.

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0 /*eyex*/, 0 /*eyey*/, 6 /*eyez*/, 0 /*lax*/, 0 /*lay*/, -1 /*laz*/, 0 /*upx*/, 1 /*upy*/, 0 /*upz*/);
glTranslatef(-15.0, -10.0, -49.0);

A modelview trafó mátrixát állítjuk be. Vagyis...
glTranslatef(-15.0, -10.0, -49.0); -> Ez egy eltolás. Tehát eltoljuk a dolgokat a [-15,-10,-49] pontba. Ez mátrixban így néz ki:

Ha a fenti pontunkat megszorozzuk ezzel a mátrixszal, akkor eredményül a [30,20,100,-2] pontot kapjuk. Homogén osztás után ez a [-15,-10,-50,1] pont lesz. Ezek után jön a gluLookAt(...), ami megmondja, hogy honnan is nézünk mi erre a pontra rá. Én a feladatban úgy emlékszem, hogy a szem z koordinátája is 0 volt, tehát a szem az origóban volt. A következő 3 koordináta adja meg a nézeti irányt, amiből kiderül, hogy a kamera a -Z irányba néz. (Ez nekünk történetesen pont jó, mert a mi pontunk is arra van.) Az utolsó 3 koordináta meg megadja a függőleges irányt. Ez az y tengely lesz.

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90 /*fov*/, 1 /*aspect*/, 1 /*fp*/, 1000 /*bp*/);

Itt a gluPerspective adja meg a perspektív transzformáció paramétereit. (A perspektív transzformációhoz érdemes megnézni a könyv 195. oldalát.)

glViewport(0 /*left*/, 0 /*bottom*/, 200 /*width*/, 200 /*height*/)

Ez pedig megadja, hogy a viewportunk 200x200-as.
A mi pontunk z=-50-nél van, így ez a pixel a képernyőn a [(-15+50)*2, (-10+50)*2] vagyis [70,80] lesz.
(Csak végig kell gondolni, hogy a z=-50-nél az a négyzet, amit lát a kamera (négyzet, mert aspect=1) [-50,-50] és [50,50] koordináták közötti terület. És ezt a négyzetet kell egy [0,0] [200,200] nagyságú négyzetre "transzformálni", ami a képernyő.) -- Mezzanine - 2008.01.03.



Magyarázat a mintamegoldáshoz: A gluPerspective első két paramétere szerencsére biztositja hogy a nézeti gúlát ne kelljen normálni (a 90 fokos látószög és az 1-es aspect miatt), igy az x-y koordináták maradnak önmaguk a perspektiv transzf. után, csak a Z és a súly változik. A Z némileg összetettebb képlet szerint - de ez itt nem is fontos, kiszámitását mellőzzük -, a súly pedig egyszerüen a Kamera-koordinátarendszer Z értékének ellentettje lesz.

Most jön a vágás, még homogén alakban. Jelen esetben egyszerüen örülünk hogy minden érték abszolútértékben kisebb mint a súly - a Zről feltételezzük, mivel nem jegyeztük meg a pontos képletét -, vagyis a pont látható lesz.

Ezután elvégezzük a homogén osztást, majd végiggondoljuk hogy ha a pont x-y koordinátái a (+-1,+-1)-es négyzet közepéről nézve (-0.3,-0.2), akkor 200x200as, bal alulról tekintett rendszerben ez (70,80)-nak fog megfelelni. Ez egyébként a képernyőtranszformáció, ahol az x-y képernyőkoordinátákat úgy kapjuk hogy a homogén-osztott x-y eszközkoordinátát hozzáadjuk 1-hez, majd ezt szorozzuk a képszélesség felével.

Mivel egyetlen pontról szólt a feladat, a Z koordinátának a képernyő rendszerben már nincs jelentősége. -- leves - 2008.01.15.


3. feladat

Milyen képfeldolgozási műveletet végeztünk?
Eredeti kép részlete:
(a sötét képen fehér pixelek voltak "elszórva")
Feldolgozott kép részlete:
(a fehér pixelek eltűntek a képről)
Adott egy kép salt and pepper típusú zajjal, majd a másodikon már nincs ilyen zaj => rank v median szűrés
Írja le a művelet lényegét! (5 pont)

4. feladat

Milyen képfeldolgozási műveletet végeztünk?
Adva volt ez a kép és a "párja" (Adott egy szürkeárnyalatos kép, a második fekete-fehér, láthatóan ditheringes de nem mátrixos. => 1 bitre redukálunk, dithering, mintha még FS-hibapropagáció is lett volna, de ez nem biztos)
Írja le a művelet lényegét! (5 pont)


-- Sirály - 2008.01.03. -- KovacsZoltan - 2008.01.03.